PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Beratungssperren oder NOWAIT, um das Warten auf gesperrte Zeilen zu vermeiden?

FOR UPDATE NOWAIT ist nur eine gute Idee, wenn Sie darauf bestehen, eine bestimmte Zeile zu sperren, was nicht ist was du brauchst. Sie wollen nur beliebige qualifizierende, verfügbare (freigeschaltete) Reihe. Der wichtige Unterschied ist folgender (unter Angabe des Handbuchs für Postgres 9.4):

Mit NOWAIT , meldet die Anweisung einen Fehler, anstatt zu warten, wenn eine ausgewählte Zeile nicht sofort gesperrt werden kann.

Identische Abfragen werden sehr wahrscheinlich versuchen, dieselbe willkürliche Auswahl zu sperren. FOR UPDATE NOWAIT wird nur mit einer Ausnahme abspringen (die die gesamte Transaktion rückgängig machen wird, es sei denn, Sie fangen den Fehler ab) und Sie müssen es erneut versuchen.

Die Lösung in meiner referenzierten Antwort auf dba.SE verwendet eine Kombination aus einfachem FOR UPDATE in Kombination mit pg_try_advisory_lock() :

pg_try_advisory_lock ähnelt pg_advisory_lock , außer dass die Funktion nicht darauf wartet, dass die Sperre verfügbar wird. Es wird die Sperre entweder sofort erhalten und true zurückgeben oder false zurückgeben, wenn die Sperre nicht sofort erworben werden kann.

Also Ihre beste Option ist ... die dritte Alternative:das neue FOR UPDATE SKIP LOCKED in Postgres 9.5, das das gleiche Verhalten ohne zusätzlichen Funktionsaufruf implementiert.

Das Handbuch für Postgres 9.5 vergleicht die beiden Optionen und erklärt den Unterschied näher:

Um zu verhindern, dass die Operation auf die Übergabe anderer Transaktionen wartet, verwenden Sie entweder den NOWAIT oder SKIP LOCKED Möglichkeit. Mit NOWAIT , meldet die Anweisung einen Fehler, anstatt zu warten, wenn eine ausgewählte Zeile nicht sofort gesperrt werden kann. Mit SKIP LOCKED , werden alle ausgewählten Zeilen, die nicht sofort gesperrt werden können, übersprungen.

Unter Postgres 9.4 oder älter Ihre nächstbeste Option ist die Verwendung von pg_try_advisory_xact_lock(id) in Kombination mit FOR UPDATE wie in der referenzierten Antwort gezeigt:

  • Postgres-UPDATE … LIMIT 1

(Auch bei einer Implementierung mit FOR UPDATE SKIP LOCKED .)

Beiseite

Genau genommen bekommt man willkürliche, nicht wirklich zufällige Picks. Das kann eine wichtige Unterscheidung sein.
Eine geprüfte Version Ihrer Frage ist in meiner Antwort auf Ihre andere Frage enthalten.