【问题标题】:Is there any diferrence between includes(:associations).references(:associations) and eager_load(:associations) in Ruby on Rails 5?Ruby on Rails 5 中的 includes(:associations).references(:associations) 和 eager_load(:associations) 之间有什么区别吗?
【发布时间】:2020-07-16 08:31:36
【问题描述】:

似乎includes(:associations).references(:associations)eager_load(:associations) 在Rails 5 中执行完全相同 SQL (LEFT OUTER JOIN)。那么我什么时候需要使用includes(:associations).references(:associations) 语法?

例如,

Parent.includes(:children1, :children2).references(:children1).where('(some conditions of children1)')

可以转换成

Parent.eager_load(:children1).preload(:children2).where('(some conditions of children1)')

我认为后者(使用eager_loadpreload 进行查询)更简单,看起来更好。

更新

我在我的环境中发现了一个奇怪的行为 (rails 5.2.4.3)。

即使我includes 几个关联并且references 仅其中一个,所有我包含的关联都是LEFT OUTER JOINed。

例如,

Parent.includes(:c1, :c2, :c3).references(:c1).to_sql

执行LEFT OUTER JOINs 所有c1、c2、c3 的SQL。 我以为它只加入 c1。

【问题讨论】:

  • 主要区别在于.includes 尝试使用一组复杂的启发式方法来判断它是否要在一个查询或两个查询中加载记录。无论如何,使用.references 是使其委托给.eager_load 的条件之一,这就是它加入:c1, :c2, :c3 的原因。如果您事先知道您将使用关联 .eager_load 以直接的方式完成这项工作。
  • 那么我什么时候需要使用includes(:associations).references(:associations) 语法呢?好吧,可能永远不会使用.eager_load

标签: ruby-on-rails activerecord ruby-on-rails-5


【解决方案1】:

确实,includes + references 最终与 eager_load 相同。就像 Rails 中的许多事情一样,您有几种方法可以实现相同的结果,在这里您将亲眼目睹。如果我在单个语句中编写它们,我总是更喜欢eager_load,因为它更明确并且是单个函数调用。

我也更喜欢eager_load,因为我认为references 是一种黑客行为。它对 SQL 生成器说“嘿,我以一种您不会检测到的方式引用此对象,因此将其包含在 JOIN 语句中”并且通常在您使用字符串传递 SQL 片段作为查询。

我唯一会使用includes(:associations).references(:associations) 语法的时候是当它是使查询工作所需的工件而不是意图声明时。 Rails Guide 给出了这个很好的例子:

Article.includes(:comments).where("comments.visible = true").references(:comments)

至于为什么引用 1 个关联会导致 3 个被 JOIN'ed,我不确定。 includes 的代码使用启发式方法来决定何时使用 JOIN 更快,何时使用 2 个单独的查询更快,第一个检索父对象,第二个检索关联对象。我很惊讶地发现often it is faster to use 2 separate queries。可能是因为无论如何查询都必须使用 1 个连接,算法认为使用 1 个大连接而不是 3 个查询会更快,或者它通常认为 1 个连接比 4 个查询快。

我一般不会使用preload,除非我有充分的理由相信它比join 快。我会单独使用includes,让算法来决定。

【讨论】:

  • 谢谢!当我使用 Hash 传递条件以包含查询时,我不知道我不需要 references。 (Rails 指南:“像这样使用 where 只会在你传递一个 Hash 时起作用。”)
猜你喜欢
  • 2022-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多