wie man sequenzielle Nummern in Postgres schnell massenhaft aktualisiert

Der Chef möchte ab 1000 für jeden Händler fortlaufende Bestellnummern erhalten.

Im Moment durchlaufe ich jeden Händler (mit Ruby) und aktualisiere die Bestellungen wie folgt:

#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 

Ich plante, dies während einer Migration auszuführen, um alle vorhandenen Aufträge so zu setzen, dass die fortlaufenden Nummern entsprechend ihrem date "ordered_at" gefüllt werden. Ich habe dies an einer Gabel der Produktionsdatenbank getestet und es dauert durchschnittlich 80 ms pro Bestellungsaktualisierung. Mit fast einer Million Auftragsdatensätzen wird dies zu viel Ausfallzeit bedeuten.

Gibt es einen schnelleren path, dies mit Postgres zu tun? Dies wäre eine einmalige Migration, die einmal ausgeführt werden muss, und gleichzeitig wird nichts weiter ausgeführt.

Ich bin kein Postgres-Experte, aber gibt es eine Möglichkeit, eine windowsfunktion mit 999 + row_number () über jede merchant_id zu verwenden und diese Zeilennummer zurück in die Spalte order_seq zu speichern?

BEARBEITEN:

Mit @ Gorden-Linoff Antwort, aber leicht modifiziert. Mir wurde klar, dass ich keine Partition über merchant_id verwenden musste, da nur einige aktive Händler das benötigten, nicht die gesamte Tabelle. Darüber hinaus muss das Update in der Auftragstabelle und nicht in der Merchants-Tabelle enthalten sein, und die Where-Klausel kann nur die ID not merchant_id und ordered_at verwenden.

Endgültige Lösung:

  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 

Das Ergebnis ist, dass dieser Vorgang 10 Minuten dauert, um 200 Händler zu verarbeiten. Die alte Methode verarbeitete ungefähr 10 Händler in 1 Stunde.

Solutions Collecting From Web of "wie man sequenzielle Nummern in Postgres schnell massenhaft aktualisiert"

Ich denke, Sie können dies mit nativem Postgres mithilfe einer aktualisierbaren Unterabfrage tun:

 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; 

BEARBEITEN:

Wenn Sie möchten, dass es für jede Händler-ID neu beginnt, verwenden Sie einfach die partition by wie 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;