#はじめに
よく耳にするけど「N+1問題」っていったい何??
どうすれば対処できるの??
となったのでまとめてメモ。
#N+1問題って?
N+1問題とは、SQLが必要以上に発行されてしまい、パフォーマンスが低下してしまう問題のこと。
??????
##つまりどういうこと??
例えば、
UserモデルとMicropostモデルがあり、
Userが複数のMicropostを持っているとします。
class User
has_many :microposts
end
class Post
belongs_to :user
end
そしてMicropost一覧ページでuserを表示するとします。
class MicropostsController < ApplicationController
def index
@microposts = Micropost.all ①
end
end
@microposts.each do |micropost|
micropost.content
micropost.user.name ②ここで発生!
end
①ここでまずMicropostモデルを全て取得
②ここでUserテーブルへのアクセスをMicropostの数だけ行う
-ループ処理の中で都度SQLを発行してしまっている
これにより、
Micropostテーブルに対して1回+Userテーブルに対してMicropostの数(N) = 1回+(N)回分のSQLが発行される。
これがN+1問題。
##解決方法
ループ処理より前にuser情報を取得しておけば良い。
こんな時使うのが、includeメソッド
モデルA.include(:モデルB) としておくとAに基づくBを取得できる
つまり、①の部分を①'に変更する
class MicropostsController < ApplicationController
def index
@microposts = Micropost.all.includes(:user) ①'
end
end
こうしておけば、 SQLは2回発行されるだけで済む。
###補足メモ
上の例ような簡単な場合はすぐにどこでN+1問題が発生しているかわかるが、もっと複雑になってきた場合、いちいちlogを見るのは大変。
こんなとき、便利なのが**「bullet」**というgem。
これを導入すると、N+1問題が発生しているページにアクセスすると、N+1が発生していることを教えてくれる。
そしてなんと解決策も一緒に教えてくれる!
便利すぎる!