Em vez de criar uma nova tabela, você também pode inserir novamente linhas exclusivas na mesma tabela depois de truncá-la. Faça tudo em uma transação . Opcionalmente, você pode descartar a tabela temporária no final da transação automaticamente com ON COMMIT DROP
. Ver abaixo.
Essa abordagem só é útil quando há muitas linhas para excluir de toda a tabela. Para apenas algumas duplicatas, use um plano DELETE
.
Você mencionou milhões de linhas. Para tornar a operação rápida, você deseja alocar buffers temporários suficientes para a sessão. A configuração deve ser ajustada antes que qualquer buffer temporário seja usado na sessão atual. Descubra o tamanho da sua mesa:
SELECT pg_size_pretty(pg_relation_size('tbl'));
Defina de temp_buffers
acordo. Arredonde generosamente porque a representação na memória precisa de um pouco mais de RAM.
SET temp_buffers = 200MB; -- example value
BEGIN;
-- CREATE TEMPORARY TABLE t_tmp ON COMMIT DROP AS -- drop temp table at commit
CREATE TEMPORARY TABLE t_tmp AS -- retain temp table after commit
SELECT DISTINCT * FROM tbl; -- DISTINCT folds duplicates
TRUNCATE tbl;
INSERT INTO tbl
SELECT * FROM t_tmp;
-- ORDER BY id; -- optionally "cluster" data while being at it.
COMMIT;
Este método pode ser superior à criação de uma nova tabela se existirem objetos dependentes. Exibições, índices, chaves estrangeiras ou outros objetos que fazem referência à tabela. TRUNCATE
faz com que você comece do zero de qualquer maneira (novo arquivo em segundo plano) e é muito mais rápido do que DELETE FROM tbl
com tabelas grandes ( DELETE
na verdade, pode ser mais rápido com tabelas pequenas).
Para tabelas grandes, é regularmente mais rápido descartar índices e chaves estrangeiras, recarregar a tabela e recriar esses objetos. No que diz respeito às restrições fk, você deve ter certeza de que os novos dados são válidos, ou você encontrará uma exceção ao tentar criar o fk.
Observe que TRUNCATE
requer um travamento mais agressivo do que DELETE
. Isso pode ser um problema para tabelas com carga simultânea pesada.
Se TRUNCATE
não for uma opção ou geralmente para tabelas pequenas e médias, há uma técnica semelhante com um CTE de modificação de dados (Postgres 9.1 +):
WITH del AS (DELETE FROM tbl RETURNING *)
INSERT INTO tbl
SELECT DISTINCT * FROM del;
-- ORDER BY id; -- optionally "cluster" data while being at it.
Mais lento para mesas grandes, porque TRUNCATE
lá é mais rápido. Mas pode ser mais rápido (e mais simples!) Para tabelas pequenas.
Se você não tiver nenhum objeto dependente, poderá criar uma nova tabela e excluir a antiga, mas dificilmente ganhará algo com essa abordagem universal.
Para tabelas muito grandes que não cabem na RAM disponível , criar uma nova tabela será consideravelmente mais rápido. Você terá que pesar isso contra possíveis problemas / sobrecarga com objetos dependentes.