代码之家  ›  专栏  ›  技术社区  ›  Dende

批量处理pgSQL查询结果

  •  0
  • Dende  · 技术社区  · 7 年前

    我编写了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\u in\u batches方法。

    我应该如何继续?

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

    1 回复  |  直到 7 年前
        1
  •  2
  •   mu is too short    7 年前

    如果你看看 find_in_batches is implemented ,您将看到该算法本质上是:

    1. 强制查询按主键排序。
    2. 添加 LIMIT 子句来匹配批次大小。
    3. (2)
    4. 如果批次小于批次大小,则无限查询已用尽,因此我们完成了。
    5. 获取最大主查询值( last_max )从你得到的批次中 (3) .
    6. 添加 primary_key_column > last_max 从查询 (2) WHERE 子句,再次运行查询,然后转至步骤 .

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

    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 子句而不是主键,但对于大型结果集,这可能会很昂贵。