除非我弄错了: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
的{{1}}:
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
有一个问题。 This article does a great job describing it。基本上,joins
将所有关联的对象加载到内存中,因此,如果查询这些关联对象的任何属性,它就不会命中数据库。同时,includes
不会将关联对象的属性加载到内存中,因此如果查询任何属性,它会对数据库进行额外的命中。
所以这是我的问题:是否可以像joins
一样进行内部联接以获得性能,但同时将所有相关对象加载到内存中,如joins
那样?
换句话说:是否可以将所有关联的对象加载到像includes
那样的内存中,但是会导致内部连接而不是子查询?
答案 0 :(得分:7)
我认为你假设JOIN
总是比两个查询更快是不正确的。它在很大程度上取决于数据库表的大小。
想象一下,您的数据库中有成千上万的拥有者和宠物。然后,即使您只想加载10条记录,您的数据库也必须首先加入所有数据库。另一方面,一个查询加载10个所有者和一个查询以加载该10个所有者的所有宠物将比JOIN
更快。
我认为两种方法都可以解决不同的问题:
joins
。includes
用于避免N + 1个查询。顺便说一下:Rails documentation注明includes
的效果优于joins
:
与简单连接相比,这通常会带来性能提升。