ActiveRecord查询中"includes"和"preload"之间有什么区别?

Pha*_*ale 35 ruby activerecord ruby-on-rails

我很难找到ActiveRecord对象的includes()和preload()的比较.有人可以解释这个区别吗?

Fre*_*ung 60

Rails有两种避免n + 1问题的方法.一个涉及创建一个基于连接的大型查询来引入您的关联,另一个涉及为每个关联创建一个单独的查询.

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

Rails的启发式方法有时会出错,或者您可能有一个特定的理由选择一种方法而不是另一种方法.preload(及其配套方法eager_load)允许您指定要使用rails的策略.

  • 本博客讨论相同的主题http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html (5认同)
  • 这篇博客文章非常实用且清晰http://blog.arkency.com/2013/12/rails4-preloading/ (3认同)

Imr*_*mad 6

详细了解请参考这个博客。

简而言之:

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 来获取数据。它也适用于提供的条件。