除非我弄错了,否则joins
具有比includes
更好的性能,因为在数据库级别:
joins
导致inner join
includes
导致subquery
通常,
inner join
比subquery
快。例子:
#app/models/owner.rb
class Owner < ActiveRecord::Base
has_many :pets
end
#app/models/pet.rb
class Pet < ActiveRecord::Base
belongs_to :owner
end
使用
rails console
:# showing how 'includes' in rails causes an IN statement which is a subquery
irb(main):001:0> @owners = Owner.all.includes(:pets)
Owner Load (2.7ms) SELECT "owners".* FROM "owners"
Pet Load (0.4ms) SELECT "pets".* FROM "pets" WHERE "pets"."owner_id" IN (1, 2, 3)
现在使用
joins
导致inner join
:irb(main):001:0> @owners = Owner.all.joins(:pets)
Owner Load (0.3ms) SELECT "owners".* FROM "owners" INNER JOIN "pets" ON "pets"."owner_id" = "owners"."id"
因此,使用
joins
似乎比使用includes
几乎总是更好,因为:includes
导致一个subquery
(IN
语句)joins
导致inner join
,通常比子查询但是,使用
joins
有一个陷阱。 This article does a great job describing it。基本上,includes
将所有关联的对象加载到内存中,因此,如果您查询那些关联的对象的任何属性,它将不会访问数据库。同时,joins
不会将关联对象的属性加载到内存中,因此,如果您查询任何属性,它将对数据库产生额外的影响。所以这是我的问题:是否可以像
joins
一样进行内部联接以提高性能,但同时又像includes
一样将所有关联的对象加载到内存中?换句话说,是否有可能像
includes
一样将所有关联的对象加载到内存中,但是会导致内部联接而不是子查询? 最佳答案
我认为您认为JOIN
总是比两个查询快的假设是不正确的。这在很大程度上取决于数据库表的大小。
想象一下,您的数据库中有成千上万的主人和宠物。然后,即使您只想加载10条记录,您的数据库也必须首先将它们连接在一起。另一方面,加载10个所有者的一个查询和加载10个所有者的所有宠物的一个查询比JOIN
快。
我认为存在两种方法可以解决不同的问题:
joins
在需要组合两个表以对两个表的数据运行查询时使用。 includes
用于避免N + 1个查询。 顺便说一句:Rails documentation注意到
includes
比joins
具有性能优势: