Eu tenho um grande teste de tabela em que em user_id 2 tem 500.000 registros. Então, eu quero excluir este registro em blocos de 100 registros, mas é dado um erro. Aqui está minha consulta:
delete from test where test_id in (select test_id
from test where User_id = 2 limit 100 )
ERRO: tupla atualizada simultaneamente
Qual é o problema. Como posso resolver isso.
Sua subseleção simples busca até 100 linhas, mas não as bloqueia contra o acesso de gravação. As transações simultâneas podem atualizar ou excluir uma ou mais dessas linhas antes de
DELETE
bloqueá-las (pelo menos com o nível de isolamento padrãoREAD COMMITTED
). Isso resultaria em sua mensagem de erro.Para se defender dessa condição de corrida, bloqueie as linhas
SELECT
comFOR UPDATE
(ou outras opções):Faça isso em uma ordem consistente para evitar impasses entre várias transações coletando bloqueios em ordem diferente e acabando bloqueando uns aos outros.
Existem soluções ainda melhores. A melhor opção seria
FOR UPDATE SKIP LOCKED
no Postgres 9.5 ou posterior:Considere atualizar para uma versão atual do Postgres.
Finalmente consegui a solução, estou apenas reindexando a tabela e está funcionando corretamente agora.
Obrigado a todos pela vossa sugestão.
Você pode querer tentar:
Separe as linhas candidatas para exclusão de Excluí-las
Por exemplo:
CREATE TEMP TABLE tmp_test1 AS SELECT test_id FROM test WHERE user_id = 2;
CREATE TEMP TABLE tmp_test2 AS SELECT * FROM tmp_test1 LIMIT 100;
{Loop enquanto tmp_test2 tem linhas}
DELETE FROM test WHERE test_id IN(SELECT test_id FROM tmp_test2);
DELETE FROM tmp_test1 WHERE test_id IN(SELECT test_id FROM tmp_test2);
TRUNCAR TABELA tmp_test2;
INSERT INTO tmp_test2 SELECT * FROM tmp_test1 LIMIT 100;
{Ciclo final}
Excluindo 0,5 milhões de linhas?
Que porcentagem da tabela os dados do usuário 2 ocupam?
Se for mais do que uma fração, considere recriar a tabela sem esses dados.