Pha*_*ale 35 ruby activerecord ruby-on-rails
我很难找到ActiveRecord对象的includes()和preload()的比较.有人可以解释这个区别吗?
Fre*_*ung 60
Rails有两种避免n + 1问题的方法.一个涉及创建一个基于连接的大型查询来引入您的关联,另一个涉及为每个关联创建一个单独的查询.
当你做includesrails时决定使用哪种策略.它默认为单独的查询方法(预加载),除非它认为您正在使用条件或顺序中的关联列.因为它只适用于连接方法,所以它使用它.
Rails的启发式方法有时会出错,或者您可能有一个特定的理由选择一种方法而不是另一种方法.preload(及其配套方法eager_load)允许您指定要使用rails的策略.
详细了解请参考这个博客。
简而言之:
Preload 在单独的查询中加载关联数据。
User.preload(:posts).to_a
# => SELECT "users".* FROM "users" SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1)
Run Code Online (Sandbox Code Playgroud)
Includes在单独的查询中加载关联数据,就像预加载一样。然而,它是聪明比
preload。但在某些情况下,它结合了查询。
如何包含更智能?
我们不能在 where 条件下使用 post table。以下查询将导致错误。
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')
Run Code Online (Sandbox Code Playgroud)
但是我们可以在 where 查询中使用 post table with 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")
Run Code Online (Sandbox Code Playgroud)
如您所见,包括从使用两个单独的查询切换到创建单个 LEFT OUTER JOIN 来获取数据。它也适用于提供的条件。