ActiveRecord查询中,“includes”和“joins”的区别是什么?

26

ActiveRecord查询中的includesjoins有什么区别?能否用以下两个关联模型对我进行解释?

class Car < ActiveRecord::Base
  belongs_to :store
end

class Store < ActiveRecord::Base
  belongs_to :owner
  has_one :car
end
7个回答

47
stores = Store.joins(:car)

这将返回所有有汽车的商店。stores[0].car将会导致另一个查询。

stores = Store.includes(:car)

这将返回所有商店,无论是否有车。stores [0] .car 不会导致另一个查询。

stores = Store.includes(:car).joins(:car)

这将返回所有拥有汽车的店铺。 stores[0].car 将不会导致另一个查询。我不建议在 has_many 关系中使用,但在 has_one 中效果很好。


31

:joins 在 SQL 中将表连接起来,:includes 则是为了避免 n+1 问题(即先执行一次查询以检索记录,然后每个关联都要执行一次查询)而预加载关联。

我建议您阅读它们在 Rails Guides 的章节,以获取更多信息。


6

:joins 返回只读对象,:includes 不会。

:joins 使用内连接,:includes 使用外连接。

:includes 的主要目的是进行贪婪加载,避免使用单独的查询加载每个对象的属性时出现N+1问题。


3

连接仅仅是将表连接起来,并返回所选字段。如果在连接查询结果上调用关联,则会再次触发数据库查询。

包含将预加载所包含的关联并将其添加到内存中。包含加载所有包含的表属性。如果在包含查询结果上调用关联,则不会触发任何查询。


0

TL; DR

连接:

a.joins(:b).to_sql
=> "SELECT \"a\".* FROM \"a\" INNER JOIN \"b\" ON \"b\".\"id\" = \"a\".\"b_id\""

包括:

a.includes(:b).to_sql
=> "SELECT \"a\".* FROM \"a\"

两者都:

a.includes(:b).joins(:b).to_sql
=> "SELECT \"a\".\"id\" AS t0_r0, \"a\".\"a_field_1\" AS t0_r1, \"a\".\"a_field_2\" AS t0_r2, \"a\".\"a_field_3\" AS t0_r3, \"b\".\"a_field_1\" AS t1_r1, \"b\".\"a_field_2\" AS t1_r2, \"b\".\"a_field_3\" AS t1_r3 FROM \"a\" INNER JOIN \"b\" ON \"b\".\"id\" = \"a\".\"plan_id\""

0

:joins 是 ActiveRecord 中 JOINS 的版本,即 SQL 请求。

Store.joins(:car).to_sql
=> SELECT stores.* FROM stores INNER JOIN cars ON cars.store_id = categories.id

背后是隐含的 INNER JOIN。因此,它确实会返回所有拥有汽车的商店(由于inner_joinleft_outer_join 的行为不同)。在这里查看更多here

:includes不是一个查询命令。 它通过在Store模型上eager_loading Car模型来解决n+1查询问题。在这里了解更多关于eager_loadinghere

stores = Store.includes(:car)

这样将返回所有的商店,并允许执行 stores.first.car 而不触发新的查询。


-1

Join:它使用惰性加载并执行内连接。连接只是将两个表简单地添加在一起。

Includes:Includes使用急切加载并执行左外连接,还可以防止N+1查询。


1
join 的解释不正确。它不是惰性加载,而是在这两个表之间建立一个 SQL 连接。您可以修改连接策略为内部或左连接等。此外,includes 不执行连接操作,而是针对每个关联执行另一个单独的查询,以获取关联关系,从而避免了惰性加载时每个关联或 1+N 问题的 1 个查询。 - Sakibul Alam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接