52

ActiveRecord オブジェクトの includes() と preload() の比較を見つけるのに苦労しています。誰でも違いを説明できますか?

4

3 に答える 3

79

Rails には、n+1 問題を回避する 2 つの方法があります。1 つは関連付けを取得するための大きな結合ベースのクエリを作成することであり、もう 1 つは関連付けごとに個別のクエリを作成することです。

includesrails を実行すると、使用する戦略が決定されます。条件または順序で関連付けの列を使用していると思わない限り、デフォルトで個別のクエリ アプローチ (プリロード) になります。それは結合アプローチでのみ機能するため、代わりにそれを使用します。

Rails のヒューリスティックは時々間違ったり、あるアプローチを他のアプローチより優先する特定の理由がある場合があります。preload(およびそのコンパニオン メソッドeager_load) を使用すると、レールで使用する戦略を指定できます。

于 2012-08-14T07:02:29.760 に答える
6

詳細については、このブログを参照してください。

要するに:

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 を作成することに切り替えます。また、提供された条件も適用されました。

于 2018-03-07T06:26:45.327 に答える
-6

apidocが言ったように、「このメソッドは非推奨であるか、最新の安定バージョンで移動されています。最後の既存のバージョン(v3.0.9)がここに表示されます。」したがって、違いは、非推奨ではないことだけが含まれることです。

于 2012-08-14T05:58:48.583 に答える