Optimieren gleichzeitiger Updates in Postgres


9

Ich führe gleichzeitig Postgres-Abfragen wie folgt aus:

UPDATE foo SET bar = bar + 1 WHERE baz = 1234

Jede Abfrage wirkt sich auf die feste K-Anzahl von Zeilen aus, und ich kann keine Möglichkeit finden, die Reihenfolge zu erzwingen, in der die Zeilen aktualisiert werden. Am Ende habe ich Deadlocks. Derzeit behebe ich das Problem, indem ich die Reihenfolge von Hand erzwinge. Dies bedeutet jedoch, dass ich viel mehr Abfragen ausführen muss als normalerweise, während gleichzeitig die Suchkomplexität von O (log N + K) auf O (K log N) erhöht wird.

Gibt es eine Möglichkeit, die Leistung zu verbessern, ohne anfällig für Deadlocks zu werden? Ich vermute, dass das Ersetzen des (baz)Index durch den (baz, id)Index funktionieren könnte, vorausgesetzt, Postgres aktualisiert die Zeilen in derselben Reihenfolge, in der sie gescannt wurden. Ist dies ein Ansatz, den es sich zu verfolgen lohnt?


Ich schlage vor, Sie fügen den CREATE TABLECode hinzu.
Ypercubeᵀᴹ

Antworten:


15

Es gibt keine ORDER BYin einem SQL UPDATEBefehl. Postgres aktualisiert die Zeilen in beliebiger Reihenfolge:

Um Deadlocks mit absoluter Sicherheit zu vermeiden, können Sie Ihre Anweisungen in serialisierbarer Transaktionsisolation ausführen . Dies ist jedoch teurer und Sie müssen sich darauf vorbereiten, Befehle bei Serialisierungsfehlern zu wiederholen.

Ihre beste Vorgehensweise besteht wahrscheinlich darin, SELECT ... ORDER BY ... FOR UPDATEeine Unterabfrage oder eine eigenständige SELECTTransaktion explizit zu sperren - in der Standardisolationsstufe "Festgeschrieben lesen". Zitat von Tom Lane auf pgsql-general :

Sollte in Ordnung sein --- Die FOR UPDATE-Sperre ist immer der letzte Schritt in der SELECT-Pipeline.

Dies sollte den Job machen:

BEGIN;

SELECT 1
FROM   foo 
WHERE  baz = 1234
ORDER  BY bar
FOR    UPDATE;

UPDATE foo
SET    bar = bar + 1
WHERE  baz = 1234;

COMMIT;

Ein mehrspaltiger Index für ist (baz, bar)möglicherweise perfekt für die Leistung. Aber da baroffensichtlich viel aktualisiert wird , könnte ein einspaltiger Index für gerade (baz)noch besser sein. Hängt von einigen Faktoren ab. Wie viele Zeilen pro baz? Sind HOT-Updates ohne den mehrspaltigen Index möglich? ...

Wenn baz gleichzeitig aktualisiert wird, gibt es noch eine unwahrscheinliche Ecke Fall Chance für Konflikte (pro Dokumentation) :

Es ist möglich, dass ein SELECTBefehl, der auf der READ COMMITTED Ebene der Transaktionsisolation ausgeführt wird ORDER BYund eine Sperrklausel verwendet, Zeilen außerhalb der Reihenfolge zurückgibt. ...

Auch, wenn Sie eine eindeutige Einschränkung beteiligt haben sollen bar, sollten Sie eine DEFERRABLEEinschränkung eindeutige Verletzungen innerhalb des gleichen Befehls zu vermeiden. Verwandte Antwort:


1
WENN ich idstattdessen nach oder nach einer anderen eindeutigen Spalte bestelle bar, sollte es keinen Eckfall oder Performance-Hit geben, oder?
Alexei Averchenko

@AlexeiAverchenko: Ja, eine eindeutige Spalte, die niemals aktualisiert wird, wäre dafür perfekt - und ein mehrspaltiger Index, der diese Spalte an zweiter Stelle enthält.
Erwin Brandstetter
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.