N+1問題とは
1つのテーブルへのSQL発行と。N回の関連デーブルへのSQL発行が発生してしまうこと。
データ量が多い大規模サービスで顕著に低いパフォーマンスが現れてしまう。
## 対象のモデル
N+1問題を確認するモデルは,tag_categoryモデルとtagモデル。
以下の2つのモデルは1対多の関係になっている。
SQL発行のタイミング
例えば以下の処理をコンソールから入力したとする。
Ruby
Tag.find(1)
このコードでは、Tagsテーブルのレコードからidが1のものを検索しTagモデルのインスタンスを生成している。
関連するモデルの値を生成するSQL
Ruby
Tag.find(1).tag_category
このコードを実行すると。
- idが1のレコードをTagsテーブルから取得する
- 検索結果のレコードからtag_catory_idを取得する
- tag_categorysテーブルから2で検索したtag_category_idのレコードを取り出す
- 検索したレコードからtag_categoryインスタンスを生成する
N+1問題が起こる仕組み
ループによってインスタンスを複数生成する場合にN+1問題が発生する。
Ruby
Tag.limit(5).each do |tag|
tag.tag_category
end
以下のコードを実行すると、
- Tagテーブルから5件のレコードを取得する
- ブロック内で書くTagインスタンスに基づくtag_categoryインスタンスを取得するループ処理を行う
よって、このコードでは5+1回SQLの発行が行われN+1問題が発生している。
N+1問題を解消する方法
アクティブレコードで以下のメソッドを使用してSQLを発行する。
- joins
- left_outer_joins
- eager_load
- preload
- includes