除非我弄错了,否则joins具有比includes更好的性能,因为在数据库级别:

  • joins导致inner join
  • includes导致subquery

  • 通常,inner joinsubquery快。

    例子:
    #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注意到includesjoins具有性能优势:

    10-08 02:36