【问题标题】:Processing pgSQL query results in batches批量处理pgSQL查询结果
【发布时间】:2017-11-12 22:15:05
【问题描述】:

我编写了 rake 任务来执行 postgreSQL 查询。该任务返回一个 Result 类的对象。

这是我的任务:

task export_products: :environment do
  results = execute "SELECT smth IN somewhere"
    if results.present?
      results
    else
      nil
    end
end

def execute sql
  ActiveRecord::Base.connection.execute sql
end

我的进一步计划是将输出分批拆分,并将这些批次逐个保存到 .csv 文件中。 我在这里卡住了。我无法想象如何为 PG::Result 调用 ActiveRecord::Batches 模块的 find_in_batches 方法。

我应该如何进行?

编辑:我有一个旧数据库的旧 sql 查询

【问题讨论】:

  • 您为什么不在模型上使用查询而不是显式编写 sql 查询的任何具体原因?
  • @Aakash Gupta 我有一个旧数据库的旧 sql 查询

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 rails-activerecord


【解决方案1】:

如果你看一下find_in_batches is implemented,你会发现算法本质上是:

  1. 强制按主键对查询进行排序。
  2. 在查询中添加LIMIT 子句以匹配批量大小。
  3. (2) 执行修改后的查询以获取批次。
  4. 对批次做任何需要做的事情。
  5. 如果批次小于批次大小,则无限查询已用尽,因此我们完成了。
  6. (3) 中获得的批次中获取最大的主查询值 (last_max)。
  7. primary_key_column > last_max添加到(2)WHERE子句的查询中,再次运行查询,然后转到步骤(4)。李>

非常简单,可以通过以下方式实现:

def in_batches_of(batch_size)
  last_max = 0 # This should be safe for any normal integer primary key.
  query = %Q{
    select whatever
    from table
    where what_you_have_now
      and primary_key_column > %{last_max}
    order by primary_key_column
    limit #{batch_size}
  }

  results = execute(query % { last_max: last_max }).to_a
  while(results.any?)
    yield results
    break if(results.length < batch_size)
    last_max = results.last['primary_key_column']
    results = execute(query % { last_max: last_max }).to_a
  end
end

in_batches_of(1000) do |batch|
  # Do whatever needs to be done with the `batch` array here
end

当然,primary_key_column 和朋友已被替换为真实值。

如果您的查询中没有主键,那么您可以使用其他一些排序良好且足够独特的列来满足您的需求。您也可以使用 OFFSET 子句代替主键,但对于大型结果集,这可能会变得很昂贵。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 2017-09-01
    • 2011-08-14
    相关资源
    最近更新 更多