ActiveRecord查询中“包含”和“连接”之间有什么区别?

时间:2011-02-01 10:27:49

标签: ruby-on-rails ruby-on-rails-3

ActiveRecord查询中“包含”和“加入”之间的区别是什么?有人可以用以下两个相关模型向我解释吗?

class Car < ActiveRecord::Base
  belongs_to :store
end

class Store < ActiveRecord::Base
  belongs_to :owner
  has_one :car
end

7 个答案:

答案 0 :(得分:34)

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

答案 1 :(得分:23)

:joins在sql中加入表,:includes急切加载关联以避免n + 1问题(执行一个查询以检索记录,然后加载每个关联一个)。 / p>

我建议您阅读Rails Guides中的相关部分以获取更多信息。

答案 2 :(得分:4)

:joins返回只读对象,:includes不是

:join使用内连接,:includes包括使用外连接。

主要原因是:include是急切加载,以避免使用单独查询加载每个对象属性的N + 1问题。

答案 3 :(得分:3)

联接将只是加入表格并带来选择的字段作为回报。如果你在连接查询结果上调用关联,它将再次触发数据库查询

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

您可以在我的这篇文章中找到详细解释和示例:Active Record Associations Tips & Tricks

答案 4 :(得分: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\""

答案 5 :(得分:0)

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

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不是查询命令。它通过eager_loading商店模型上的Car模型解决了n + 1查询问题。查看更多一个eager_loading here

stores = Store.includes(:car)

因此将返回所有商店,并允许执行stores.first.car而无需触发新查询。

答案 6 :(得分:-1)

Join:它使用延迟加载并执行内部连接。 join 简单地将两个表相加

Includes:Includes 使用预先加载并执行左外连接,并且包含也可以防止 N+1 查询。