这更像是一个“事情为什么会这样”的问题,而不是一个“我不知道怎么做”的问题。

拉关联记录的福音是使用: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

Am I missing something? I have an app with half a dozen associations and on one screen I display data from all of them. Seems like it would be better to have one join-ed query instead of 6 individuals. I know that performance-wise it's not always better to do a join rather than individual queries (in fact if you're going by time spent, it looks like the two individual queries above are faster than the join), but after all the docs I've been reading I'm surprised to see :include not working as advertised.

也许Rails意识到了性能问题,除非在某些情况下才会加入?


当前回答

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

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

其他回答

看来:include功能在Rails 2.1中有所改变。Rails过去在所有情况下都执行连接,但出于性能原因,在某些情况下更改为使用多个查询。Fabio Akita的这篇博客文章有一些关于这个变化的很好的信息(参见标题为“优化的快速加载”部分)。

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

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

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

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

除了性能方面的考虑外,还有功能上的差异。 当你连接评论时,你是在请求有评论的帖子——默认情况下是一个内部连接。 当你包含评论时,你是在请求所有的帖子——一个外部连接。

博士tl;

我从两个方面对它们进行对比:

joins—用于有条件地选择记录。

includes—在结果集的每个成员上使用关联时。

完整版

join用于过滤来自数据库的结果集。你可以用它在表上做set操作。把它看作是执行集合理论的where子句。

Post.joins(评论)

职位。Where ('id in (select post_id from comments)')

除了如果有一个以上的评论,你会得到重复的帖子与连接。但是每个帖子都有评论。你可以用distinct来纠正这个错误:

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.

寓意是,当您想要执行条件集操作时使用连接,当您要在集合的每个成员上使用关系时使用包含。