这更像是一个“为什么事情会这样”的问题,而不是一个“我不知道怎么做”的问题...
因此,在提取您知道要使用的关联记录时,最好使用: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)
它 * 是 * 走捷径,因为它一次拉取所有注解,但它仍然不是一个连接(所有文档似乎都是这么说的)。
Post.all(:joins => :comments)
日志显示:
Post Load (6.0ms) SELECT "posts".* FROM "posts"
INNER JOIN "comments" ON "posts".id = "comments".post_id
我错过了什么吗?我有一个应用程序,有六个关联,我在一个屏幕上显示所有这些关联的数据。似乎有一个连接的查询比6个单独的查询更好。我知道,从性能方面来说,连接并不总是比单独的查询更好(实际上,如果按所用时间计算,上面两个单独的查询似乎比连接更快),但是在我阅读了所有文档之后,我惊讶地发现:include
并不像广告上说的那样工作。
也许Rails * 认识到了性能问题,除了在某些情况下,它不会加入?
8条答案
按热度按时间6kkfgxo01#
.joins
将只连接表并返回所选字段.如果你调用连接查询结果上的关联,它将再次激发数据库查询:includes
将立即加载包含的关联并将其添加到内存中。:includes
将加载所有包含的表属性。如果对包含查询结果调用关联,则不会触发任何查询guz6ccqo2#
连接和包含语句之间的区别在于,使用包含语句会生成一个更大的SQL查询,该查询会将其他表中的所有属性加载到内存中。
例如,如果您有一个充满评论的表,并且您使用a:joins =〉users来获取所有用户信息以进行排序等,它将工作正常,并且比:include花费更少的时间,但是假设您想要显示评论以及用户名、电子邮件等。要使用:joins来获取信息,它将必须为它获取的每个用户进行单独的SQL查询,而如果您使用:include,则此信息已准备就绪。
很好的例子:
http://railscasts.com/episodes/181-include-vs-joins
chhkpiq43#
我最近阅读了更多关于Rails中
:joins
和:includes
之间的区别的文章。下面是我所理解的内容的解释(有例子:))请考虑以下情况:
联接:
:joins在两个表之间执行内部联接。因此
将提取**user_id(注解表的)等于user.id(用户表)的所有记录。**因此,如果您这样做
您将得到一个如下所示的空数组。
此外,连接不会将连接表加载到内存中。
如您所见,
comment_1.user.age
将在后台再次触发数据库查询以获取结果包括:
:includes在两个表之间执行左外部联接。因此
将产生**一个包含注解表中所有记录的连接表。**因此,如果您这样做
它将获取comments.user_id为nil的记录,如图所示。
在内存中加载这两个表。
正如您所注意到的,comment_1.user.age只是从内存中加载结果,而不需要在后台触发数据库查询。
ippsafx74#
除了性能方面的考虑之外,还有一个功能上的区别。当你加入评论时,你要求的是有评论的帖子--默认情况下是一个内部连接。当你包括评论时,你要求的是所有帖子--一个外部连接。
wnrlj8wa5#
我从两个方面对它们进行了对比:
联接-用于有条件地选择记录。
includes-对结果集得每个成员使用关联时.
联接用于筛选来自数据库的结果集。您可以使用它对表执行集合操作。可以将其视为执行集合论的where子句。
Post.joins(:comments)
与相同
Post.where('id in (select post_id from comments)')
除了如果有多个评论,你会得到重复的帖子,但是每个帖子都是有评论的帖子。你可以用distinct来纠正这个问题:
相反,
includes
方法将确保在引用关系时没有额外的数据库查询(这样我们就不会进行n + 1次查询)寓意是,当你想做条件集合运算时,使用
joins
,当你想对集合的每个成员使用关系时,使用includes
。yptwkmov6#
.joins作为数据库连接工作,它连接两个或多个表,并从后端(数据库)提取选定的数据。
.includes作为数据库的左连接工作。它加载左侧的所有记录,不具有右侧模型的相关性。它用于提前加载,因为它加载内存中的所有关联对象。如果我们对includes查询结果调用关联,则它不会对数据库触发查询,它只是从内存中返回数据,因为它已经在内存中加载了数据。
wlwcrazw7#
'joins'仅用于连接表,当您在连接上调用关联时,它将再次触发查询(这意味着将触发多个查询)
在本例中,SQL总数为11
但使用'includes'将立即加载包含的关联并将其添加到内存中(在第一次加载时加载所有关联),并且不会再次触发查询
当您获取包含的记录时,如@records= User.includes(:organizations).where(“organizations.user_id = 1”),则查询将
records.map{|U形|u.organization.name}不会触发任何查询
guykilcj8#
:include
功能似乎在Rails 2.1中发生了变化。Rails在所有情况下都用于执行连接,但出于性能原因,在某些情况下改为使用多个查询。Fabio秋田的This blog post提供了一些关于此变化的有用信息(请参见“优化的Eager Loading”一节)。