Active Record in_batches 与 find_in_batches

Vat*_*ain 5 activerecord ruby-on-rails

我想对数据库中的数百万条记录执行批处理操作。

根据ActiveRecord文档,有两种方法可以执行批量操作,即#find_in_batches& #in_batchesEnumerator但是,除了一个返回 an而另一个返回 an之外,我似乎找不到它们之间的任何区别ActiveRecord Relation

因此,考虑到它们具有不同的性能,我想知道哪种在哪种情况下表现更好。并且,除了原始 SQL 之外,是否还有更好的方法来有条件地更新数百万行?

pet*_*who 8

简而言之,find_in_batches生成每批找到的记录in_batches,同时生成ActiveRecord::Relation对象

所以下面的代码:

Post.find_in_batches do |group|
   group.each { |post| puts post.title }
end
Run Code Online (Sandbox Code Playgroud)

每批次仅向数据库发送一个查询,以检索该批次的所有帖子数据:

Post.find_in_batches do |group|
   group.each { |post| puts post.title }
end
Run Code Online (Sandbox Code Playgroud)

然而:

Post.in_batches do |group|
   group.each { |post| puts post.title }
end
Run Code Online (Sandbox Code Playgroud)

将每批发送两个查询到数据库。获取该批次帖子 ID 的第一个查询:

SELECT "posts".* FROM "posts" WHERE ...
Run Code Online (Sandbox Code Playgroud)

第二个查询获取该批次的所有帖子数据:

Post.in_batches do |group|
   group.each { |post| puts post.title }
end
Run Code Online (Sandbox Code Playgroud)

更多细节:

如果您在此处查看这两个函数的源代码,您将看到find_in_batches实际上调用in_batches时传入了load: true参数。然而,默认值loadfalsein_batches

如果您进一步查看in_batches使用 value 的 for 部分load,它将如下所示:

SELECT "posts"."id" FROM "posts" WHERE ...
Run Code Online (Sandbox Code Playgroud)

原始解释可以在这里找到:https://www.codehub.com.vn/Difference- Between-find_in_batches-vs-in_batches-in-Ruby-on-Rails


tam*_*koo 5

您必须查看源代码才能了解此处的性能差异 -

def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
  relation = self
  unless block_given?
    return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
      total = apply_limits(relation, start, finish).size
      (total - 1).div(batch_size) + 1
    end
  end

  in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore) do |batch|
    yield batch.to_a
  end
end
Run Code Online (Sandbox Code Playgroud)

in_batches请注意如何调用该方法以及如何将结果存储在数组中。这会占用更多内存。in_batches因此这里是一种更有效的方法。

  • 没有任何上下文我同意。但是,仅仅因为一个调用另一个并不意味着它的性能较差......它只取决于当前未知的用例。 (2认同)