Atom UPDATE .. SELECT in Postgres
Ich Baue ein queuing-Mechanismus von Arten. Dort sind Reihen von Daten, die verarbeitet werden müssen, und ein status-flag. Ich bin mit einem update .. returning
Klausel zu verwalten:
UPDATE stuff
SET computed = 'working'
WHERE id = (SELECT id from STUFF WHERE computed IS NULL LIMIT 1)
RETURNING *
Ist die geschachtelte select-Teil die gleichen lock wie das update, oder muss ich eine race-condition hier? Wenn ja, ist die innere select benötigen, um ein select for update
?
InformationsquelleAutor der Frage kolosy | 2012-07-18
Du musst angemeldet sein, um einen Kommentar abzugeben.
Während Erwin ' s Vorschlag ist eventuell die einfachste Weg, um das richtige Verhalten (so lange, wie Sie wiederholen Sie Ihre Transaktion, wenn Sie eine Ausnahme mit
SQLSTATE
von 40001), queuing-Anwendungen, die durch Ihre Natur dazu neigen, besser zu arbeiten mit Anfragen blockieren, um eine chance zu nehmen, Ihre biegen Sie an der Warteschlange als mit dem PostgreSQL-Implementierung vonSERIALIZABLE
Transaktionen, die es ermöglicht eine höhere Parallelität und ist auch etwas "optimistisch" über die Chancen der Kollision.Die Beispiel-query, in der Frage, wie es steht, in der Standard -
READ COMMITTED
transaction isolation level erlauben würde, zwei (oder mehr) gleichzeitige verbindungen zu sowohl der "Anspruch" der gleichen Zeile aus der Warteschlange. Was passieren wird ist diese:UPDATE
phase.COMMIT
oderROLLBACK
von T1.id
entspricht), und auch die "Ansprüche" der Reihe.Kann geändert werden, um korrekt zu arbeiten (wenn Sie eine version von PostgreSQL, die es ermöglicht die
FOR UPDATE
- Klausel in einer Unterabfrage). Fügen Sie einfachFOR UPDATE
am Ende der Unterabfrage wählt die id, und dies wird geschehen:COMMIT
oderROLLBACK
von T1.In der
REPEATABLE READ
oderSERIALIZABLE
transaction isolation level, die schreib-Konflikt wirft einen Fehler, die Sie fangen konnte, und zu bestimmen, wurde eine Serialisierung der Fehler basierend auf den SQLSTATE, und versuchen Sie es erneut.Wenn Sie wollen in der Regel SERIALISIERBARE Transaktionen, aber Sie wollen vermeiden, Wiederholungen in den Warteschlangen-Bereich, könnten Sie in der Lage sein, zu erreichen, dass durch die Verwendung eines Beratungs-lock.
InformationsquelleAutor der Antwort kgrittn
Wenn Sie die nur Benutzerdie Abfrage sollte in Ordnung sein. Insbesondere gibt es keine race-condition oder deadlock innerhalb der Abfrage selbst (zwischen der äußeren Abfrage und der Unterabfrage). Ich zitiere das Handbuch hier:
Für gleichzeitige Verwendungdie Sache kann noch komplizierter werden. Sie wäre auf der sicheren Seite mit
SERIALIZABLE
transaction-Modus:Müssen Sie zur Vorbereitung für die Serialisierung Fehler, und wiederholen Sie Ihre Abfrage in einem solchen Fall.
Aber ich bin mir nicht ganz sicher, ob das nicht übertrieben ist. Ich frag @kgrittn zu stoppen .. er ist die Experte mit Parallelität und serialisierbare Transaktionen ..
Und das Tat er. 🙂
Beste aus beiden Welten
Ausführen der Abfrage in der Standard-Transaktionsmodus
READ COMMITTED
.Für PostgreSQL 9.5 oder höher verwenden
FOR UPDATE SKIP LOCKED
. Siehe:Für ältere Versionen überprüfen Sie den Zustand
computed IS NULL
explizit in der äußerenUPDATE
:Als @kgrittn, beraten im Kommentar zu seiner Antwort diese Abfrage könnte sich leeren, ohne dass etwas getan hat, in dem (unwahrscheinlichen) Fall miteinander verwoben, die mit einer gleichzeitigen Transaktion.
Daher, es würde funktionieren, ähnlich wie die erste Variante, die in der Transaktion Modus
SERIALIZABLE
würden Sie haben, um zu wiederholen - nur eben ohne die Leistungseinbußen.Das einzige problem: Während der Konflikt ist sehr unwahrscheinlich, da das Fenster der Gelegenheit ist nur so winzig ist, kann es passieren das unter der schweren Last. Sie konnte nicht sicher sagen, ob es gibt schließlich keine mehr Zeilen sind Links.
Wenn das egal ist (so wie in deinem Fall), Sie sind hier fertig.
Wenn es das tut, werden absolut sicher, starten Sie eine weitere Abfrage mit explizite sperren nachdem Sie sich ein leeres Ergebnis. Wenn diese fruchtlos bleiben, sind Sie fertig. Wenn nicht, fahren Sie Fort.
In plpgsql, könnte es so Aussehen:
Dass sollte Ihnen das beste aus beiden Welten: performance und Zuverlässigkeit.
InformationsquelleAutor der Antwort Erwin Brandstetter