ARのjoinまわりのメソッドを勉強した
ARのjoinまわりのメソッドを勉強した。N+1を解消するのにとても便利。
joins
- アソシエーションをキャッシュしない
- アソシエーションを検索条件でだけつかいたいときに有効
- 内部的には普通にjoinしてる
preload
- アソシエーションをキャッシュする
- 必要なテーブルをまとめて別のselect文で読み込みするのでクエリは2回に発行される
- あまりjoinしたくないでかいテーブルに有効
- joinしてないので、絞り込み条件に関連テーブルを使えない
- index系のAPIでの N+1 の解消に有効
eager_load
- アソシエーションをキャッシュする
- joinする
- joinしているので、絞り込み条件に関連テーブルを使える
includes
- preload と eager_load を適切に使い分けてくれる
- join先で絞り込んでいたら eager_load
- してなかったら preload
merge
- joinsをチェインすることができる
- ちょっと初見だとどんなクエリになるか判断つかないかもしれない
Comment.joins(:entry).where(Entry.merge(:draft)) # scopeを使うとき Comment.joins(:entry).merge(Entry.where(published_at: nil)) # scopeを使わないとき
これらのメソッドを使ってもどうしてもN+1が解決できない場合
最後に、これらのメソッドを使ってもどうしてもN+1が解決できない場合は、
一旦Rubyの配列に確保してしまってからループの中でRubyの方のselect メソッドを使うことで解決した。
# N+1 の発生を防ぐため, あらかじめまとめて読み込んでおく user_favs = @user.favs.where( target_id: Articles.published.pluck(:id) ).to_a users = list.map do |elem| user_fav = user_favs.select{ |f| f.id == elem.fav_id } # Array#select を使う # user_favを使って諸々の処理をする end