52

我正在努力寻找 ActiveRecord 对象的 include() 和 preload() 的比较。谁能解释其中的区别?

4

3 回答 3

79

Rails 有两种方法可以避免 n+1 问题。一个涉及创建一个基于大连接的查询来拉入您的关联,另一个涉及对每个关联进行单独的查询。

当你这样做时,includesrails 决定为你使用哪种策略。它默认为单独的查询方法(预加载),除非它认为您正在使用您的条件或顺序中的关联列。因为这只适用于连接方法,所以它使用它。

Rails 的启发式方法有时会出错,或者您可能有特定原因偏爱一种方法而不是另一种方法。preload(及其配套方法eager_load)允许您指定您希望 Rails 使用的策略。

于 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')

但是我们可以在 where 查询中使用 post 表include

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")

如您所见,包括从使用两个单独的查询到创建单个 LEFT OUTER JOIN 以获取数据的切换。它还应用了提供的条件。

于 2018-03-07T06:26:45.327 回答
-6

正如 apidoc 所说,“此方法已被弃用或在最新的稳定版本上移动。最后一个现有版本(v3.0.9)显示在这里。” 所以不同之处在于包括不被弃用。

于 2012-08-14T05:58:48.583 回答