ActiveRecord オブジェクトの includes() と preload() の比較を見つけるのに苦労しています。誰でも違いを説明できますか?
3 に答える
Rails には、n+1 問題を回避する 2 つの方法があります。1 つは関連付けを取得するための大きな結合ベースのクエリを作成することであり、もう 1 つは関連付けごとに個別のクエリを作成することです。
includes
rails を実行すると、使用する戦略が決定されます。条件または順序で関連付けの列を使用していると思わない限り、デフォルトで個別のクエリ アプローチ (プリロード) になります。それは結合アプローチでのみ機能するため、代わりにそれを使用します。
Rails のヒューリスティックは時々間違ったり、あるアプローチを他のアプローチより優先する特定の理由がある場合があります。preload
(およびそのコンパニオン メソッドeager_load
) を使用すると、レールで使用する戦略を指定できます。
詳細については、このブログを参照してください。
要するに:
Preload は、別のクエリで関連付けデータを読み込みます。
User.preload(:posts).to_a
# => SELECT "users".* FROM "users" SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1)
インクルードは、プリロードと同様に、別のクエリで関連付けデータをロードします。ただし、よりもスマートです
preload
。ただし、クエリを組み合わせる場合もあります。
インクルードはよりスマートですか?
where 条件で post テーブルを使用することはできません。次のクエリはエラーになります。
User.preload(:posts).where("posts.desc='ruby is awesome'")
# =>
SQLite3::SQLException: no such column: posts.desc:
SELECT "users".* FROM "users" WHERE (posts.desc='ruby is awesome')
ただし、 includeを使用した where クエリでpost テーブルを使用できます
User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a
# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
"posts"."title" AS t1_r1,
"posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
WHERE (posts.desc = "ruby is awesome")
ご覧のとおり、データを取得するために 2 つの個別のクエリを使用することから、単一の LEFT OUTER JOIN を作成することに切り替えます。また、提供された条件も適用されました。
apidocが言ったように、「このメソッドは非推奨であるか、最新の安定バージョンで移動されています。最後の既存のバージョン(v3.0.9)がここに表示されます。」したがって、違いは、非推奨ではないことだけが含まれることです。