PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Evitare i deadlock di PostgreSQL durante l'esecuzione di operazioni di aggiornamento ed eliminazione in blocco

Utilizza il blocco a livello di riga esplicito nelle sottoquery ordinate in tutte le query concorrenti .
(SELECT non compete con i blocchi di scrittura.)

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;

In questo modo, le righe vengono bloccate in un ordine coerente come consigliato nel manuale.

Supponendo che id_A , id_B non sono mai aggiornati, anche rare complicazioni di casi angolari come dettagliate nella casella "Attenzione" nel manuale non sono possibili.

Pur non aggiornando le colonne chiave, puoi utilizzare la modalità di blocco più debole FOR NO KEY UPDATE . Richiede Postgres 9.3 o successivo.

L'altro (lento e certo) l'opzione consiste nell'utilizzare il livello di isolamento serializzabile per le transazioni concorrenti. Dovresti prepararti per errori di serializzazione, nel qual caso devi riprovare il comando.