【问题标题】:In Rails 3.2, how to "pluck_in_batches" for a very large table在 Rails 3.2 中,如何为一个非常大的表“pluck_in_batches”
【发布时间】:2015-02-08 06:39:41
【问题描述】:

我有一个巨大的表 Foo,我需要从中提取某个字段 Foo.who 中的所有值。

该数组有数百万行,但who 列中只有几千个不同的值。

如果桌子更小,我当然会使用Foo.pluck(:who)

如果我使用Foo.find_in_batches do |a_batch|,每个集合都是 Foo 记录的数组,而不是 Foo 记录的 activerecord 集合,所以我不能使用 .pluck() 和 AFAIK 提取 who 列的唯一方法是通过类似.map(&:who) 遍历数组。

有没有一种方法可以分批从 Foo 中提取 who 列,而不需要遍历每个批次的每个元素来提取 who 列?

【问题讨论】:

  • 对于 rails 4+,检查 this gist 以获取 pluck_in_batches 方法

标签: ruby-on-rails activerecord pluck


【解决方案1】:

in_batches 已经在后台运行pluck(:id)(如果load 参数是false,这是默认值)并产生与where(id: ids_from_pluck) 的关系。那么是否可以直接从关系中获取 id 列表,从而避免在 DB 中运行另一个查询:

Foo.in_batches do |relation|
  ids = relation.where_values_hash['id']
end

这应该适用于 Rails 5.x 和 6.x,但依赖于 in_batches 的实现细节,因此将来可能会改变。

【讨论】:

    【解决方案2】:

    在 Rails 5 中,您可以使用:

    Foo.in_batches do |relation|
      values = relation.pluck(:id, :name, description)
      ...
    end
    

    更新:为了防止内存泄漏,请使用:

    Foo.uncached do
      Foo.in_batches do |relation|
        values = relation.pluck(:id, :name, description)
        ...
      end
    end
    

    【讨论】:

    • 您能否详细说明内存泄漏问题以及Foo.uncached 如何/为什么提供帮助?如果这也适用于 Rails 6.0/6.1,我也很感兴趣。
    • @GuiGS,这不是真正的“泄漏”。默认情况下,Rails 将缓存所有查询结果,这种情况可能会占用太多 RAM。稍后将释放此内存。 Foo.uncached 将禁用缓存。见api.rubyonrails.org/classes/ActiveRecord/QueryCache/…
    • 我明白了。看起来 in_batches 已经这样做了github.com/rails/rails/blob/…(至少对于 Rails >= 5.2)。不确定它是否仍适用于relation.pluck。
    【解决方案3】:

    试试这个:

    Foo.select(:id, :who).find_in_batches do |a_batch|
      ...
    end
    

    【讨论】:

    • 那仍然会创建 ActiveRecord 对象,我认为 OP 出于内存和速度的原因试图避免这种情况。
    • 不确定上面的评论是什么意思。为了清楚起见,select 将更改底层 SQL 以仅返回相关值。 find_in_batches 已经使用 AR 模型,问题是如何限制返回的数据。这是我需要的。
    猜你喜欢
    • 2014-07-05
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多