老板想要每个商家的顺序订单号,从 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 专家,但有没有办法在每个 merchant_id 上使用 999+row_number() 来使用窗口函数,并将该 row_number 保存回 order_seq 列?
编辑:
使用@Gorden-Linoff 的回答,但稍作修改。我意识到我不需要对 merchant_id 使用分区,因为只有一些活跃的商家需要这个,而不是整个表。另外更新需要在 orders 表上,而不是 merchants 表上,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 个商家。
最佳答案
我认为您可以使用可更新的子查询对 native 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;
关于sql - 如何快速批量更新postgres中的序列号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24765132/