はじめに
私は、今までRailsでN+1問題を解決する際、「とりあえず includes を使っておけばいい」というイメージを持っていました。
しかし、現場ではpreloadやeager_loadを使うこともあるので、
今回は自分自身の頭の整理も兼ねて、includes、preload、eager_load の挙動の違いを簡単にまとめてみました。
preload
関連レコードを別クエリ(IN句)で取得。
JOINしないためシンプルでメモリに優しいが、関連先テーブルの条件(whereなど)で絞り込みができない。
eager_load
LEFT OUTER JOINを使って1つのクエリでまとめて取得。
関連先テーブルでの条件絞り込みが可能になるが、レコード数が多いと重くなりやすい。
includes
基本は preload と同じく別クエリで引くが、関連先への条件指定があることを検知すると、自動的に eager_load(JOIN方式)に切り替えてくれるよしなにやってくれるメソッド。
まとめ
-
基本方針: メモリに優しい
preloadを優先して使う。 -
関連先で絞り込みたい時:
eager_loadを明示的に使う。 -
注意点:
includesはよしなにやってくれて便利だが、裏側でどちらのクエリが発行されているか曖昧になりやすいため、意図を明確にするならpreloadとeager_loadを使い分ける。
