Sql 如何快速批量更新postgres中的序号
boss希望每个商户都有顺序的订单号,从1000开始 现在,我正在使用ruby遍历每个商家,并更新订单,如下所示:Sql 如何快速批量更新postgres中的序号,sql,ruby-on-rails,postgresql,Sql,Ruby On Rails,Postgresql,boss希望每个商户都有顺序的订单号,从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|
#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
我计划在迁移过程中运行此程序,以设置所有现有订单,使其按照其在日期的订单号填充序列号。我在fork of the production数据库上测试了这一点,每次订单更新平均需要80毫秒。由于订单记录接近100万条,这将导致太多的停机时间
对于本地博士后,有没有更快的方法?这将是一次迁移,需要运行一次,并且没有其他并发操作
我不是postgres专家,但有没有办法在每个商户id上使用999+行号的窗口功能,并将该行号保存回订单列
编辑:
使用@Gorden Linoff回答,但稍作修改。我意识到我不需要在商户id上使用分区,因为只有一些活动商户需要分区,而不是整个表。此外,更新需要在orders表上,而不是merchants表上,where子句只能使用id not 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个商户。我认为您可以使用可更新的子查询对本机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重新开始,则只需使用分区:
不过,我希望每个商户id的序列号从1000开始。似乎此查询应在订单上更新,而不是商户:更新o set o.order_seq=seqnum+999 from select o.*,按订单的行号,as seqnum from orders o,其中商户id=1 o;但这会产生错误:错误:关系o不存在第1行:更新o集合o.order_seq=seqnum+999^@sketchfemme。哎呀。我使用了SQL Server语法,Postgres语法有点不同,两者都使用了类似的from子句进行更新,但细节不同。我接受这一正确答案,尽管我需要做一些调整,尤其是表名。我将编辑我的问题以包含我的最终解决方案
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;