PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Evitando impasses do PostgreSQL ao realizar operações de atualização e exclusão em massa


Use bloqueio em nível de linha explícito em subconsultas ordenadas em todas as consultas concorrentes .
(SELECT não compete com bloqueios de gravação.)

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;

Dessa forma, as linhas são bloqueadas em ordem consistente, conforme recomendado no manual.

Supondo que id_A , id_B nunca são atualizados, mesmo as complicações raras do caso de canto, como detalhadas na caixa "Cuidado" no manual, não são possíveis.

Embora não esteja atualizando as colunas de chave, você pode usar o modo de bloqueio mais fraco FOR NO KEY UPDATE . Requer Postgres 9.3 ou posterior.

O outro (lento e com certeza) é usar o Nível de Isolamento Serializável para transações concorrentes. Você teria que se preparar para falhas de serialização e, nesse caso, seria necessário repetir o comando.