我正在尝试理解用于批量检索记录的Active Record find_each方法。
如果一篇帖子有很多评论(数千条评论),而我想呈现每条评论,我可以这样做:
@post.comments.each{| comment |…}
但如果我这样做,它会更快吗:
@post.comments.find_each{| comment |…}?
第二个查询有效吗?
我看到的是,通过在find_each之前执行@post.comments,已经获得了每条帖子的所有评论,所以用find_each结束查询可能是多余的?!
这是rails应用程序视图文件夹中的完整代码块:
json.comments @post.comments.find_each do |comment|
json.rating comment.rating
json.content comment.content
end
谢谢
@post.comments.find_each
正确。当您调用@post.comments
时,它创建的查询不会立即执行。这就是为什么您可以将其他查询方法(如where和order等)链接到此关联。(为了可读性,sql日志被截断)
>> comments = Post.first.comments; nil;
Post Load (0.8ms)
=> nil
# NOTE: ^ no comments are loaded yet, until we need to output the result
>> comments
Comment Load (2.0ms)
=> [#<Comment:0x00007f2ef1733328 id: 1, post_id: 1>, ...] # <= array of 2000 comments
当each
方法被链接时,所有的注释都会加载到内存中,当您有数千条记录时,这是一个问题。
>> Post.first.comments.each{|c| print "." }
Post Load (0.6ms)
# NOTE: executes one query for comments
Comment Load (1.4ms)
.................................................. # <= 2000 dots
=> [#<Comment:0x00007f2ef1560be0 id: 1, post_id: 1>, ...]
当find_each
方法被链接时,默认以1000为一批检索注释:
>> Post.first.comments.find_each{|c| print "." }
Post Load (0.6ms)
# NOTE: executes query to get 1000 comments at a time
Comment Load (0.8ms)
.................................................. # <= 1000 dots
Comment Load (0.8ms)
.................................................. # <= 1000 dots
Comment Load (0.4ms)
# no more comments
=> nil
您也可以指定:batch_size
:
>> Post.first.comments.find_each(batch_size: 100){|c| print "." }
Post Load (0.7ms)
# NOTE: get comments in batches of 100
Comment Load (0.6ms)
.................................................. # <= 100 dots
Comment Load (0.5ms)
.................................................. # <= 100 dots
# 21 queries in total
=> nil
https://api.rubyonrails.org/classes/ActiveRecord/Batches.html#method-i-find_each