3

我只是在学习 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 视频,作者正在查看:includevs :join,我在控制台上看到了输出 SQL,这是一个大型 SQL 查询,但它只是一个查询。我只是想知道这是应该的还是我错过了什么?

4

2 回答 2

7

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

一种方法是每个关联有一个查询:首先加载所有节目(1 个查询),然后加载所有艺术家(第二个查询)。如果您当时包含一个关于艺术家的关联,这将是第三个查询。所有这些查询都是简单的查询,尽管这确实意味着在您的特定情况下不会获得任何优势。因为查询是分开的,所以您不能做诸如通过子关联订购顶级(显示)之类的事情。

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

Active Record 将默认使用第一种策略(预加载),除非它认为您的查询条件或订单正在引用关联,在这种情况下它会回退到第二种方法。您可以通过使用 preloadoreager_load代替来强制使用策略:includes

于 2013-01-08T16:36:22.370 回答
1

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

更好的解释:Active Record Querying Eager Loading

于 2013-01-08T15:07:25.787 回答