sql >> Base de Datos >  >> RDS >> PostgreSQL

Evitar interbloqueos de PostgreSQL al realizar operaciones de actualización y eliminación masivas

Usar bloqueo explícito a nivel de fila en subconsultas ordenadas en todas las consultas de la competencia .
(SELECT no compite con los bloqueos de escritura).

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;

De esta manera, las filas se bloquean en el mismo orden que se recomienda en el manual.

Suponiendo que id_A , id_B nunca se actualizan, incluso las complicaciones raras de casos de esquina como se detalla en el cuadro "Precaución" en el manual no son posibles.

Mientras no actualice las columnas clave, puede usar el modo de bloqueo más débil FOR NO KEY UPDATE . Requiere Postgres 9.3 o posterior.

El otro (lento y seguro) es usar el nivel de aislamiento serializable para transacciones competidoras. Debería prepararse para las fallas de serialización, en cuyo caso debe volver a intentar el comando.