【问题标题】:how to quickly mass update sequential numbers in postgres如何在postgres中快速批量更新序列号
【发布时间】:2014-07-17 05:34:26
【问题描述】:

老板想要每个商家的顺序订单号,从 1000 开始。

现在我正在遍历每个商家(使用 ruby​​),并像这样更新订单:

#running all of this in a migration
add_column :orders, :order_seq, :integer


Merchant.find_each do |merchant|
  order_seq = 999
  merchant.orders.order(:ordered_at).find_each do |order|
    order.update_column(:order_seq, order_seq+=1)
  end
end

我计划在迁移期间运行此程序,以将所有现有订单设置为根据其ordered_at 日期填充序列号。我在生产数据库的一个分支上对此进行了测试,每个订单更新平均需要 80 毫秒。由于订单记录接近一百万,这将导致过多的停机时间。

有没有更快的方法来使用本机 postgres 做到这一点?这将是一次性迁移,需要运行一次,并且不会同时进行任何其他操作。

我不是 postgres 专家,但有没有办法在每个 Mercer_id 上使用 999+row_number() 的窗口函数并将该 row_number 保存回 order_seq 列?

编辑:

使用@Gorden-Linoff 回答,但稍作修改。我意识到我不需要在 Mercer_id 上使用分区,因为只有一些活跃的商家需要这个,而不是整个表。另外更新需要在orders表上,而不是在merchans表上,where子句只能使用id而不是merchant_id和ordered_at。

最终解决方案:

  Merchant.active.find_each(batch_size: 100) do |merchant|
    statement = "update orders set order_seq = o.seqnum + 999 " +
      "from (select o.id, row_number() " +
      " over (order by ordered_at) as seqnum from orders o where o.merchant_id = #{merchant.id}" +
      ") o where orders.id = o.id"
    ActiveRecord::Base.connection.execute(statement)
  end

结果是这个操作需要 10 分钟来处理 200 个商户。旧方法在 1 小时内处理了大约 10 个商家。

【问题讨论】:

    标签: sql ruby-on-rails postgresql


    【解决方案1】:

    我认为您可以使用可更新的子查询对本机 Postgres 执行此操作:

    update merchants
        set order_seq = m.seqnum + 999
        from (select m.*, row_number() over (order by ordered_at) as seqnum
              from merchants m
             ) m
        where merchants.merchant_id = m.merchant_id and
              merchants.ordered_at = m.ordered_at;
    

    编辑:

    如果您希望它为每个商家 ID 重新开始,那么只需使用 partition by:

    update merchants
        set order_seq = m.seqnum + 999
        from (select m.*, row_number() over (partition by merchant_id
                                             order by ordered_at
                                            ) as seqnum
              from merchants m
             ) m
        where merchants.merchant_id = m.merchant_id and
              merchants.ordered_at = m.ordered_at;
    

    【讨论】:

    • 我希望每个商家 ID 的序列号从 1000 开始。似乎这个查询应该更新订单,而不是商家:update o set o.order_seq = seqnum +999 from (select o.*, row_number() over (order by ordered_at) as seqnum from orders o wherecommerce_id = 1) o ;但这会产生错误:错误:关系“o”不存在第1行:更新o集o.order_seq = seqnum + 999 ^
    • @sketchfemme 。 . .哎呀。我使用了 SQL Server 语法,而 Postgres 语法略有不同(两者都对updates 使用类似的from 子句,但细节不同)。
    • 我接受这是正确的答案,但我需要进行一些调整,尤其是表名。我将编辑我的问题以包含我的最终解决方案
    猜你喜欢
    • 1970-01-01
    • 2015-07-09
    • 2020-06-03
    • 2010-11-03
    • 2019-08-17
    • 2023-04-01
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    相关资源
    最近更新 更多