PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Éviter les blocages PostgreSQL lors de l'exécution d'opérations de mise à jour et de suppression en masse

Utiliser un verrouillage explicite au niveau de la ligne dans les sous-requêtes ordonnées dans toutes les requêtes concurrentes .
(SELECT n'entre pas en concurrence avec les verrous en écriture.)

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 cette façon, les lignes sont verrouillées dans un ordre cohérent, comme indiqué dans le manuel.

En supposant que id_A , id_B ne sont jamais mis à jour, même les rares complications de cas d'angle comme celles détaillées dans la case "Attention" du manuel ne sont pas possibles.

Sans mettre à jour les colonnes de clé, vous pouvez utiliser le mode de verrouillage plus faible FOR NO KEY UPDATE . Nécessite Postgres 9.3 ou version ultérieure.

L'autre (lent et bien sûr) consiste à utiliser le niveau d'isolement sérialisable pour les transactions concurrentes. Vous devrez vous préparer aux échecs de sérialisation, auquel cas vous devrez réessayer la commande.