【发布时间】:2012-08-14 05:38:48
【问题描述】:
我正在努力寻找 ActiveRecord 对象的 include() 和 preload() 的比较。谁能解释一下区别?
【问题讨论】:
标签: ruby-on-rails ruby activerecord
我正在努力寻找 ActiveRecord 对象的 include() 和 preload() 的比较。谁能解释一下区别?
【问题讨论】:
标签: ruby-on-rails ruby activerecord
Rails 有两种方法可以避免 n+1 问题。一个涉及创建一个基于大连接的查询来拉入您的关联,另一个涉及为每个关联创建一个单独的查询。
当您执行includes 时,rails 决定为您使用哪种策略。它默认为单独的查询方法(预加载),除非它认为您正在使用您的条件或顺序中的关联列。因为这只适用于连接方法,所以它使用它。
Rails 的启发式方法有时会出错,或者您可能有特定原因偏爱一种方法而不是另一种方法。 preload(及其配套方法eager_load)允许您指定您希望rails 使用的策略。
【讨论】:
详细了解请参考this博客。
简而言之:
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 来获取数据。它还应用了提供的条件。
【讨论】:
正如 apidoc 所说,“此方法已被弃用或在最新的稳定版本上移动。此处显示了最新的现有版本 (v3.0.9)。”所以不同之处在于只包括不弃用。
【讨论】: