0
1

More than 3 years have passed since last update.

N+1問題とは?

Posted at

はじめに

よく耳にするけど「N+1問題」っていったい何??
どうすれば対処できるの??
となったのでまとめてメモ。

N+1問題って?

N+1問題とは、SQLが必要以上に発行されてしまい、パフォーマンスが低下してしまう問題のこと。
??????

つまりどういうこと??

例えば、
UserモデルとMicropostモデルがあり、
Userが複数のMicropostを持っているとします。

app/models/user.rb
class User
 has_many :microposts
end
app/models/micropost.rb
class Post
 belongs_to :user
end

そしてMicropost一覧ページでuserを表示するとします。

app/controllers/micropost_controller.rb
class MicropostsController < ApplicationController
  def index
    @microposts = Micropost.all  ①
  end
end
app/views/microposts/index.html.erb

@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を取得できる

つまり、①の部分を①'に変更する

app/controllers/micropost_controller.rb
class MicropostsController < ApplicationController
  def index
    @microposts = Micropost.all.includes(:user)  ①'
  end
end

こうしておけば、 SQLは2回発行されるだけで済む。

補足メモ

上の例ような簡単な場合はすぐにどこでN+1問題が発生しているかわかるが、もっと複雑になってきた場合、いちいちlogを見るのは大変。

こんなとき、便利なのが「bullet」というgem。
これを導入すると、N+1問題が発生しているページにアクセスすると、N+1が発生していることを教えてくれる。
そしてなんと解決策も一緒に教えてくれる!
便利すぎる!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1