Rails 5 上的 Ruby 中的 includes(:associations).references(:associations) 和 eager_load(:associations) 之间有什么区别吗?
Is there any diferrence between includes(:associations).references(:associations) and eager_load(:associations) in Ruby on Rails 5?
似乎 includes(:associations).references(:associations)
和 eager_load(:associations)
在 Rails 中执行 完全相同的 SQL (LEFT OUTER JOIN) 5.那么什么时候需要使用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_load
和preload
查询)更简单,看起来更好。
更新
我在我的环境中发现了一个奇怪的行为 (rails 5.2.4.3
)。
即使我 includes
有几个关联并且 references
只有其中一个,所有 我包含的关联都是 LEFT OUTER JOIN
ed。
例如,
Parent.includes(:c1, :c2, :c3).references(:c1).to_sql
执行 SQL,其中 LEFT OUTER JOIN
是 c1、c2、c3 的全部。
我以为它只加入 c1.
的确,includes
+ references
最终与 eager_load
相同。与 Rails 中的许多事情一样,您可以通过多种方式实现相同的结果,在这里您将亲眼目睹。如果我将它们写在单个语句中,我总是更喜欢 eager_load
因为它更明确并且是单个函数调用。
我也更喜欢 eager_load
,因为我认为 references
是一种 hack。它对 SQL 生成器说“嘿,我以一种你不会检测到的方式引用这个对象,所以将它包含在 JOIN 语句中”并且通常在你使用 String 传递 SQL 片段作为查询的一部分。
我唯一一次使用 includes(:associations).references(:associations)
语法是当它是使查询工作所需的工件而不是意图声明时。 Rails Guide 给出了这个很好的例子:
Article.includes(:comments).where("comments.visible = true").references(:comments)
至于为什么引用 1 个关联会导致 3 个关联,我不确定。 includes
的代码使用启发式方法来决定何时使用 JOIN 更快,何时使用 2 个单独的查询更快,第一个查询检索父对象,第二个检索关联对象。我很惊讶地发现 often it is faster to use 2 separate queries。可能是因为查询无论如何都必须使用 1 个连接,算法认为使用 1 个大连接比使用 3 个查询更快,或者它通常认为 1 个连接比 4 个查询快。
我一般不会使用 preload
,除非我有充分的理由相信它比 join
快。我会单独使用 includes
,让算法决定。
似乎 includes(:associations).references(:associations)
和 eager_load(:associations)
在 Rails 中执行 完全相同的 SQL (LEFT OUTER JOIN) 5.那么什么时候需要使用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_load
和preload
查询)更简单,看起来更好。
更新
我在我的环境中发现了一个奇怪的行为 (rails 5.2.4.3
)。
即使我 includes
有几个关联并且 references
只有其中一个,所有 我包含的关联都是 LEFT OUTER JOIN
ed。
例如,
Parent.includes(:c1, :c2, :c3).references(:c1).to_sql
执行 SQL,其中 LEFT OUTER JOIN
是 c1、c2、c3 的全部。
我以为它只加入 c1.
的确,includes
+ references
最终与 eager_load
相同。与 Rails 中的许多事情一样,您可以通过多种方式实现相同的结果,在这里您将亲眼目睹。如果我将它们写在单个语句中,我总是更喜欢 eager_load
因为它更明确并且是单个函数调用。
我也更喜欢 eager_load
,因为我认为 references
是一种 hack。它对 SQL 生成器说“嘿,我以一种你不会检测到的方式引用这个对象,所以将它包含在 JOIN 语句中”并且通常在你使用 String 传递 SQL 片段作为查询的一部分。
我唯一一次使用 includes(:associations).references(:associations)
语法是当它是使查询工作所需的工件而不是意图声明时。 Rails Guide 给出了这个很好的例子:
Article.includes(:comments).where("comments.visible = true").references(:comments)
至于为什么引用 1 个关联会导致 3 个关联,我不确定。 includes
的代码使用启发式方法来决定何时使用 JOIN 更快,何时使用 2 个单独的查询更快,第一个查询检索父对象,第二个检索关联对象。我很惊讶地发现 often it is faster to use 2 separate queries。可能是因为查询无论如何都必须使用 1 个连接,算法认为使用 1 个大连接比使用 3 个查询更快,或者它通常认为 1 个连接比 4 个查询快。
我一般不会使用 preload
,除非我有充分的理由相信它比 join
快。我会单独使用 includes
,让算法决定。