N+1問題とは
N+1問題とは、SQLが実行される際、クエリの回数が無駄に多くなってしまい、パフォーマンスを低下させてしまうことです。
※クエリとは、データベースからデータを抽出したり操作したりといった処理を行うための命令のことです。
つまり、必要なデータ(N)を抽出するごとに、毎度1回多く(+1)SQLが発行されてしまい、処理に時間がかかってしまいます。
というよりは、毎度必要なデータを抽出しにいく手間を無くすと考えた方がわかりやすいかもしれません。
なぜN+1問題を回避すべきなのか?
前述のとおり、パフォーマンスを低下させるからです。
また、大量のSQLが発行されることでコンピューターにも負担がかかります。
データ量が少なければあまり問題になりませんが数万、数十万とデータを抽出するとなると、高負荷になりパフォーマンスの低下につながることは容易に想像できるはずです。
いつまでたっても表示・更新されないWebサービスは嫌ですよね。私も嫌ですし、そもそもユーザーが離脱します。
具体例
ここでは、UserモデルとPostモデルが一対多の関係であるとします。
下記のコードでは、投稿した人の名前を表示しようとしています。
posts = Post.all
posts.each do |post|
p post.users.name
end
一見問題なさそうですが、これこそがまさにN+1問題が発生しているのです。
例えば投稿が100個あった場合、このコードだと101回SQLが発行していることになります。
ではこれを解決するにはどうすればよいのでしょうか?
N+1の解決策
解決策は一つではありませんが、もっとも簡単な方法としてはincludes
メソッドを使用することです。
posts = Post.includes(:users).all
posts.each do |post|
p post.users.name
end
最初の一行目に.includes(:users)
を追加しただけです。
こうすることで
N+1問題は、とくに一対多の関係で発生しやすいです。
他のテーブルからデータを取得するときにはとくに気をつけましょう。
まとめ
- N+1問題とは、クエリの回数が無駄に多くなってしまい、パフォーマンスを低下させてしまうこと
- とくに一対多の関係で発生することが多い
-
includes
メソッドを使うことで解決できる
覚えてしまえばそんなに難しくないので、さくっと学習しておきましょう。
こちらの動画も参考になったのでおすすめです。
【Ruby on Rails】必ず知っておきたい N+1 問題(SQL)N+1 problem on Ruby on Rails