これは何?
preload, eager_load, includesを見かけるたびに、あれ、これってどういう挙動をするんだっけ?と調べているのでメモ。
前提
Tips
結論
- eager_load
- 1対1あるいはN対1のアソシエーションをJOINする場合に使う
- preload
- 多対多のアソシエーションの場合に使う
- joins
- メモリの使用量を必要最低限に抑えたい場合に使う
- JOINした先のデータを参照せず、絞り込み結果だけが必要な場合に使う
- includes
- 使わない。私は断固として使わない。使ってるコードを見つけたら絶対に駆逐する。
Eager loading と Lazy loading
Eager loading
- 予めメモリ上にActive Recordで情報を保持する方法。
- ActiveRecordのメソッドで言えば、preload, eager_load, includesなど。
- pros : 素早いレンダリングが可能になる。
- cons : アソシエーションしているテーブルにある情報が膨大な場合、大量のメモリを消費することになる。
Lazy loading
- JOINしたテーブルの情報が必要になった時に SQLを発行する方法。
- ActiveRecordのメソッドで言えば、joinsなど。
- pros : メモリを確保する量はEagerLoadingにくらべて少なくなる。
- cons : JOINするテーブルを参照するたびSQLを発行するためWebサイト表示パフォーマンスを悪くする場合があります(N+1問題)
それぞれのメソッドの比較
メソッド | クエリ | アソシエーション先の参照 | デメリット |
---|---|---|---|
eager_load | LEFT JOIN | できる | JOIN先のデータ多いほど速度が低下する |
preload | SELECT | できない | データ量が多いと、IN句が肥大化してメモリを圧迫する |
joins | INNER JOIN | できる | N+1問題が発生するかも |
incleds | SELECT または LEFT JOIN | できる | 理解していないと予想外の挙動をするかも |
- どんな時に使うべきか??
【おまけ】includesの挙動について
- includesしたテーブルでwhereによる絞り込みを行っている
- includesしたassociationに対してjoinsかreferencesも呼んでいる
- 任意のassociationに対してeager_loadも呼んでいる のうちいずれかに該当すると、eager_loadが呼ばれる
- 例 下記の場合は、eager_loadの挙動をします。
app/controllers/articles_controller.rb class ArticlesController < ApplicationController def index @articles = Article.includes(:reviews, :users).where(reviews: { article_id: 1}) end end
下記の場合は、preloadの挙動をします。
app/controllers/articles_controller.rb class ArticlesController < ApplicationController def index @articles = Article.includes(:reviews, :users) end end