【发布时间】:2014-04-06 10:18:31
【问题描述】:
我正在使用 Ruby on Rails 4,我想了解为什么在急切加载过程中运行进一步的 SQL 查询,即使数据是急切加载的。也就是说,我有以下代码可以正确加载:comments:
@articles = @current_user.articles.includes(:comments)
当上述代码运行时,我使用以下代码“跟踪”记录器中发生的事情:
@articles.each do |article|
logger.debug article.comments
end
然后记录器说:
Article Load (0.4ms) SELECT ...
Comment Load (0.5ms) SELECT ... WHERE `articles`.`id` IN (...)
#<ActiveRecord::Associations::CollectionProxy [#<Comment id: 1, title: "Hello A">, #<Comment id: 2, title: "Hello B">]>
#<ActiveRecord::Associations::CollectionProxy [#<Comment id: 3, title: "Hello A">, #<Comment id: 4, title: "Hello C">]>
#<ActiveRecord::Associations::CollectionProxy [#<Comment id: 5, title: "Hello D">, #<Comment id: 6, title: "Hello E">]>
...
以上输出表明预加载按预期工作:没有 N+1 问题,因为在运行 article.comments 时加载了 ActiveRecord::Associations::CollectionProxy 对象。
但是,当我尝试运行如下代码时(注意find_by 子句):
@articles.each do |article|
logger.debug article.comments.find_by(:title => "Hello A")
end
然后记录器说:
Article Load (0.4ms) SELECT ...
Comment Load (0.5ms) SELECT ... WHERE `articles`.`id` IN (...)
Comment Load (0.4ms) SELECT ... AND `comments`.`title` = 'HELLO A'
#<Comment id: 1, title: "Hello A">
Comment Load (0.4ms) SELECT ... AND `comments`.`title` = 'HELLO A'
#<Comment id: 3, title: "Hello A">
Comment Load (0.4ms) SELECT ... AND `comments`.`title` = 'HELLO A'
nil
...
以上输出表明预加载没有按预期工作:每条评论都会运行一个 SQL 查询。
所以,我的问题/疑问是:
- 为什么在最后一种情况下,
find_by子句使急切加载不起作用(注意:即使在我使用find_by以外的子句“过滤”article.comments时也会发生这种情况)? - Ruby on Rails 是否应该将已加载到
ActiveRecord::Associations::CollectionProxy对象中的数据作为数组处理以避免撞到数据库?! - 如何解决问题以避免在最后一种情况下出现 N+1 问题?
【问题讨论】:
标签: sql ruby-on-rails ruby ruby-on-rails-4 eager-loading