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_buffersacordo. 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. TRUNCATEfaz com que você comece do zero de qualquer maneira (novo arquivo em segundo plano) e é muito mais rápido do que DELETE FROM tblcom tabelas grandes ( DELETEna 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 TRUNCATErequer um travamento mais agressivo do que DELETE. Isso pode ser um problema para tabelas com carga simultânea pesada.
Se TRUNCATEnã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 TRUNCATElá é 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.