我正在使用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">]>
...
上面的输出表明,急切的加载正在按预期的方式进行:由于ActiveRecord::Associations::CollectionProxy
运行时已加载对象,因此没有N + 1问题article.comments
。
但是,当我尝试运行如下代码时(请注意该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
子句使急切的加载不起作用(请注意:即使在我article.comments
使用而不是子句“过滤”的情况下,它也会发生find_by
)?ActiveRecord::Associations::CollectionProxy
对象中的数据作为数组进行处理,从而避免访问数据库?只是确认一下:David Underwood是正确的,find_by
它将进行数据库调用。事实上,find_by
基本上只是一个包装where
和take
,这的确会让一个DB调用。
完成您要查找的内容的另一种方法是,通过使用find
方法,将收集代理简单地视为一个数组,如下所示:
@articles.each do |article|
logger.debug article.comments.find {|comment| comment.title == "Hello A"}
end
更新:
我不得不承认,这有点令人生厌。
以您想要的方式完成此操作的方法是添加另一个has_many
专门包含所需过滤条件的关系,如下所示:
class Article < ActiveRecord::Base
has_many :hello_A_comments, -> { where(title: "Hello A") }, class_name: "Comment"
# rest of class
end
然后,您渴望使用此新关联进行加载,如下所示:
@articles = @current_user.articles.includes(:hello_A_comments)
这部分非常重要:现在,您不是通过原始:comments
关联方法访问关联,而是通过新hello_A_comments
方法访问关联,如下所示:
@articles.first.hello_a_comments
不幸的是,如您所见,此方法不是很动态,而遗憾的是,在急切加载的情况下,我不知道如何在关联中考虑可变条件。这个答案可能是一个很好的参考资源,但是在急于加载的情况下,老实说,我认为它不可能。如果这是一个问题,那么您可能会遇到前面提到的数组方法。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句