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

Vermeiden von PostgreSQL-Deadlocks beim Ausführen von Massenaktualisierungs- und Löschvorgängen

Verwenden Sie explizites Sperren auf Zeilenebene in geordneten Unterabfragen in allen konkurrierenden Suchanfragen .
(SELECT konkurriert nicht mit Schreibsperren.)

DELETE

DELETE FROM table_name t
USING (
   SELECT id_A, id_B
   FROM   table_name 
   WHERE  id_A = ANY(array_of_id_A)
   AND    id_B = ANY(array_of_id_B)
   ORDER  BY id_A, id_B
   FOR    UPDATE
   ) del
WHERE  t.id_A = del.id_A
AND    t.id_B = del.id_B;

UPDATE

UPDATE table_name t
SET    val_1 = 'some value'
     , val_2 = 'some value'
FROM  (
   SELECT id_A, id_B
   FROM   table_name 
   WHERE  id_A = ANY(array_of_id_A)
   AND    id_B = ANY(array_of_id_B)
   ORDER  BY id_A, id_B
   FOR    NO KEY UPDATE  -- Postgres 9.3+
-- FOR    UPDATE         -- for older versions or updates on key columns
   ) upd
WHERE  t.id_A = upd.id_A
AND    t.id_B = upd.id_B;

Auf diese Weise werden Zeilen in konsistenter Reihenfolge gesperrt, wie im Handbuch empfohlen.

Angenommen, id_A , id_B werden nie aktualisiert, selbst seltene Komplikationen in Ausnahmefällen, wie im Abschnitt "Achtung" im Handbuch beschrieben, sind nicht möglich.

Während Schlüsselspalten nicht aktualisiert werden, können Sie den schwächeren Sperrmodus FOR NO KEY UPDATE verwenden . Erfordert Postgres 9.3 oder höher.

Die andere (langsam und sicher) Option ist die Verwendung der serialisierbaren Isolationsstufe für konkurrierende Transaktionen. Sie müssten sich auf Serialisierungsfehler vorbereiten, in diesem Fall müssen Sie den Befehl wiederholen.