为什么ActiveRecord:包含两个查询?

时间:2013-01-08 14:40:58

标签: ruby-on-rails ruby rails-activerecord

我只是在学习ActiveRecord和SQL,我的印象是:include执行一个SQL查询。所以,如果我这样做:

Show.first :include => :artist

它将执行一个查询,该查询将返回第一个节目和艺术家。但是看看生成的SQL,我看到两个查询:

[2013-01-08T09:38:00.455705 #1179] DEBUG -- :   Show Load (0.5ms)  SELECT `shows`.* FROM `shows` LIMIT 1
[2013-01-08T09:38:00.467123 #1179] DEBUG -- :   Artist Load (0.5ms)  SELECT `artists`.* FROM `artists` WHERE `artists`.`id` IN (2)

我看到了一个Railscast视频,其中作者正在:include vs :join,我在控制台上看到输出SQL并且它是一个大型SQL查询,但它只是一个查询。我只是想知道这是不是应该是这样,还是我错过了什么?

2 个答案:

答案 0 :(得分:6)

Active Record有两种方式可以预先加载关联。 :includes会根据一些启发式触发其中任何一个。

一种方法是每个关联有一个查询:首先加载所有节目(1个查询),然后加载所有艺术家(第二个查询)。如果你当时包括一个关于艺术家的协会,这将是第三个查询。所有这些查询都是简单的查询,但它确实意味着在您的特定情况下不会获得任何好处。因为查询是分开的,所以你不能通过子关联和类似的事情来命令顶层(显示)。

第二种方法是在一个基于大连接的查询中加载所有内容。这总是产生一个查询,但它更复杂 - 包括每个关联1个连接,并且将结果集转换回ruby对象的代码也更复杂。还有一些其他的极端情况:无法处理多态的belongs_to,并且在同一级别包含多个has_many会产生非常大的结果集。)

Active Record将默认使用第一个策略(preload),除非它认为您的查询条件或顺序引用了关联,在这种情况下它将回退到第二种方法。您可以使用preloadeager_load代替:includes强制使用的策略。

答案 1 :(得分:1)

使用:includes是一种提供预先加载的解决方案。它将在您的示例中加载最多两个查询。如果您要更改查询Show.all :include => :artist。这也只会调用两个查询。

更好的解释:Active Record Querying Eager Loading