ActiveRecord查询中的includes和joins有什么区别?能否用以下两个关联模型对我进行解释?
class Car < ActiveRecord::Base
belongs_to :store
end
class Store < ActiveRecord::Base
belongs_to :owner
has_one :car
end
ActiveRecord查询中的includes和joins有什么区别?能否用以下两个关联模型对我进行解释?
class Car < ActiveRecord::Base
belongs_to :store
end
class Store < ActiveRecord::Base
belongs_to :owner
has_one :car
end
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
中效果很好。
:joins
在 SQL 中将表连接起来,:includes
则是为了避免 n+1 问题(即先执行一次查询以检索记录,然后每个关联都要执行一次查询)而预加载关联。
我建议您阅读它们在 Rails Guides 的章节,以获取更多信息。
:joins 返回只读对象,:includes 不会。
:joins 使用内连接,:includes 使用外连接。
:includes 的主要目的是进行贪婪加载,避免使用单独的查询加载每个对象的属性时出现N+1问题。
连接仅仅是将表连接起来,并返回所选字段。如果在连接查询结果上调用关联,则会再次触发数据库查询。
包含将预加载所包含的关联并将其添加到内存中。包含加载所有包含的表属性。如果在包含查询结果上调用关联,则不会触发任何查询。
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\""
: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_join
,left_outer_join
的行为不同)。在这里查看更多here。
而:includes
不是一个查询命令。 它通过在Store模型上eager_loading
Car模型来解决n+1查询问题。在这里了解更多关于eager_loading
here。
stores = Store.includes(:car)
这样将返回所有的商店,并允许执行 stores.first.car
而不触发新的查询。
Join:它使用惰性加载并执行内连接。连接只是将两个表简单地添加在一起。
Includes:Includes使用急切加载并执行左外连接,还可以防止N+1查询。
join
的解释不正确。它不是惰性加载,而是在这两个表之间建立一个 SQL 连接。您可以修改连接策略为内部或左连接等。此外,includes
不执行连接操作,而是针对每个关联执行另一个单独的查询,以获取关联关系,从而避免了惰性加载时每个关联或 1+N 问题的 1 个查询。 - Sakibul Alam