提问



这更像是为什么这样做的事情这个问题,而不是我不知道如何做到这一点的问题......


所以关于拉动你知道你将要使用的相关记录的福音是使用:include,因为你将获得一个连接并避免一大堆额外的查询:


Post.all(:include => :comments)


但是当你查看日志时,没有发生加入:


Post Load (3.7ms)   SELECT * FROM "posts"
Comment Load (0.2ms)   SELECT "comments.*" FROM "comments" 
                       WHERE ("comments".post_id IN (1,2,3,4)) 
                       ORDER BY created_at asc) 


它是采用快捷方式,因为它会立即提取所有注释,但它仍然不是连接(这是所有文档似乎都说的)。我可以获得连接的唯一方法是使用:joins而不是:include:


Post.all(:joins => :comments)


日志显示:


Post Load (6.0ms)  SELECT "posts".* FROM "posts" 
                   INNER JOIN "comments" ON "posts".id = "comments".post_id


我错过了什么吗?我有一个有六个关联的应用程序,在一个屏幕上我显示所有这些数据。似乎最好有一个加入查询而不是6个人。我知道在性能方面,做一个连接而不是单个查询并不总是更好(事实上,如果你按时间花费,看起来上面的两个单独的查询比连接更快),但毕竟我一直在阅读的文件我很惊讶地看到:include没有像宣传的那样工作。


也许Rails 认识到性能问题并且在某些情况下不会加入?

最佳参考


看来:include的功能随着Rails 2.1而改变了。 Rails用于在所有情况下进行连接,但出于性能原因,它在某些情况下被更改为使用多个查询。 Fabio Akita撰写的这篇博文有关于这一变化的一些很好的信息(参见优化的渴望加载一节)。[31]

其它参考1


.joins将只加入表格并返回选定的字段。如果在连接查询结果上调用关联,它将再次触发数据库查询


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


我的博文有一些差异的详细解释[32]

其它参考2


连接和包含之间的区别在于,使用include语句会生成一个更大的SQL查询,将来自其他表的所有属性加载到内存中。


例如,如果您有一个充满注释的表,并且您使用:joins => users来提取所有用户信息以进行排序等,它将正常工作并且花费的时间少于:include,但是您要显示注释以及用户名,电子邮件等。要使用:join来获取信息,它必须为它所获取的每个用户创建单独的SQL查询,而如果您使用:include,则此信息可供使用。


好例子:


http://railscasts.com/episodes/181-include-vs-joins[33]

其它参考3


除了性能方面的考虑外,还存在功能差异。
当您加入评论时,您要求发布具有评论的帖子 - 默认情况下为内部联接。
当您包含评论时,您要求所有帖子 - 外部联接。

其它参考4


我最近在轨道上阅读了:joins:includes之间的差异。这是我理解的解释(用例子:))


考虑这种情况:



  • 用户has_many评论和评论belongs_to用户。

  • User模型具有以下属性:Name(字符串),Age(整数)。 Comment模型具有以下属性:Content,user_id。对于注释,user_id可以为null。



连接:



:join在两个表之间执行内部联接。从而


Comment.joins(:user)

#=> <ActiveRecord::Relation [#<Comment id: 1, content: "Hi I am Aaditi.This is my first   comment!", user_id: 1, created_at: "2014-11-12 18:29:24", updated_at: "2014-11-12 18:29:24">, 
     #<Comment id: 2, content: "Hi I am Ankita.This is my first comment!", user_id: 2, created_at: "2014-11-12 18:29:29", updated_at: "2014-11-12 18:29:29">,    
     #<Comment id: 3, content: "Hi I am John.This is my first comment!", user_id: 3, created_at: "2014-11-12 18:30:25", updated_at: "2014-11-12 18:30:25">]>


将获取所有记录,其中user_id(评论表)等于user.id(用户表)。因此,如果你这样做


Comment.joins(:user).where("comments.user_id is null")

#=> <ActiveRecord::Relation []>


您将获得一个空数组,如图所示。


此外,连接不会将连接的表加载到内存中。因此,如果你这样做


comment_1 = Comment.joins(:user).first

comment_1.user.age
#=>←[1m←[36mUser Load (0.0ms)←[0m  ←[1mSELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1←[0m  [**"id", 1**]
#=> 24


如您所见,comment_1.user.age将在后台再次触发数据库查询以获得结果


包括:



:includes在两个表之间执行左外连接。从而


Comment.includes(:user)

#=><ActiveRecord::Relation [#<Comment id: 1, content: "Hi I am Aaditi.This is my first comment!", user_id: 1, created_at: "2014-11-12 18:29:24", updated_at: "2014-11-12 18:29:24">,
   #<Comment id: 2, content: "Hi I am Ankita.This is my first comment!", user_id: 2, created_at: "2014-11-12 18:29:29", updated_at: "2014-11-12 18:29:29">,
   #<Comment id: 3, content: "Hi I am John.This is my first comment!", user_id: 3, created_at: "2014-11-12 18:30:25", updated_at: "2014-11-12 18:30:25">,    
   #<Comment id: 4, content: "Hi This is an anonymous comment!", user_id: nil, created_at: "2014-11-12 18:31:02", updated_at: "2014-11-12 18:31:02">]>


将导致一个包含评论表中所有记录的联接表。因此,如果你这样做


Comment.includes(:user).where("comment.user_id is null")
#=> #<ActiveRecord::Relation [#<Comment id: 4, content: "Hi This is an anonymous comment!", user_id: nil, created_at: "2014-11-12 18:31:02", updated_at: "2014-11-12 18:31:02">]>


它将获取comments.user_id为零的记录,如图所示。


此外,还包括加载内存中的表。因此,如果你这样做


comment_1 = Comment.includes(:user).first

comment_1.user.age
#=> 24


您可以注意到,comment_1.user.age只是从内存加载结果而不在后台触发数据库查询。

其它参考5


.joins用作数据库连接,它连接两个或多个表并从后端(数据库)获取所选数据。


.includes作为数据库的左连接工作。它加载了左侧的所有记录,没有右侧模型的相关性。它用于急切加载,因为它加载内存中的所有关联对象。如果我们在包含查询结果上调用关联,那么它不会在数据库上触发查询,它只是从内存中返回数据,因为它已经在内存中加载了数据。

其它参考6


TL;博士


我以两种方式对比它们:


加入 - 用于条件选择记录。


包括 - 在结果集的每个成员上使用关联时。


更长的版本


连接旨在过滤来自数据库的结果集。您可以使用它来对表进行设置操作。可以将其视为执行集合论的where子句。


Post.joins(:comments)


是相同的


Post.where('id in (select post_id from comments)')


除非如果有多个注释,您将通过联接返回重复的帖子。但是每篇文章都会发表评论。你可以用不同的方法纠正这个:


Post.joins(:comments).count
=> 10
Post.joins(:comments).distinct.count
=> 2


在契约中,includes方法将简单地确保在引用关系时没有其他数据库查询(这样我们就不会进行n + 1个查询)


Post.includes(:comments).count
=> 4 # includes posts without comments so the count might be higher.


道德是,当你想要进行条件集操作时使用joins并在你打算在集合的每个成员上使用关系时使用includes

其它参考7


连接只是用于连接表,当你在连接上调用关联时,它将再次触发查询(这意味着许多查询将触发)


lets suppose you have tow model, User and Organisation
User has_many organisations
suppose you have 10 organisation for a user 
@records= User.joins(:organisations).where("organisations.user_id = 1")
QUERY will be 
 select * from users INNER JOIN organisations ON organisations.user_id = users.id where organisations.user_id = 1

it will return all records of organisation related to user
and @records.map{|u|u.organisation.name}
it run QUERY like 
select * from organisations where organisations.id = x then time(hwo many organisation you have)


在这种情况下,SQL的总数是11


但随着
includes将急切加载包含的关联并将它们添加到内存中(在第一次加载时加载所有关联),而不是再次触发查询


当你获得包含类似的记录时
@ records=User.includes(:organizations).where(organisations.user_id=1)
然后查询将


select * from users INNER JOIN organisations ON organisations.user_id = users.id where organisations.user_id = 1
and 


 select * from organisations where organisations.id IN(IDS of organisation(1, to 10)) if 10 organisation
and when you run this 


@ records.map {| U | u.organisation.name}
    没有查询会触发