Вместо создания новой таблицы вы также можете повторно вставить уникальные строки в ту же таблицу после ее усечения. Сделайте все это в одной транзакции . При желании вы можете автоматически удалить временную таблицу в конце транзакции с помощью ON COMMIT DROP
. Смотри ниже.
Этот подход полезен только тогда, когда есть много строк, которые нужно удалить из всей таблицы. Для нескольких дубликатов, используйте простой DELETE
.
Вы упомянули миллионы строк. Для выполнения операции fast необходимо выделить достаточно временных буферов для сеанса. Настройка должна быть отрегулирована до того, как будет использоваться любой временный буфер в текущем сеансе. Узнайте размер вашего стола:
SELECT pg_size_pretty(pg_relation_size('tbl'));
Установите temp_buffers
соответственно. Обильно округляйте, потому что представление в памяти требует немного больше оперативной памяти.
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;
Этот метод может быть лучше создания новой таблицы , если существуют зависимые объекты. Представления, индексы, внешние ключи или другие объекты, ссылающиеся на таблицу. TRUNCATE
в любом случае позволяет начинать с чистого листа (новый файл в фоновом режиме) и на намного быстрее, чем DELETE FROM tbl
с большими таблицами (DELETE
на самом деле быстрее с столики).
Для больших таблиц это регулярно быстрее для удаления индексов и внешних ключей, пополнения таблицы и воссоздания этих объектов. Что касается ограничений fk, вы должны быть уверены, что новые данные действительны, конечно, или вы столкнетесь с исключением при попытке создать fk.
Обратите внимание, что TRUNCATE
требует более агрессивной блокировки, чем DELETE
. Это может быть проблемой для таблиц с большой одновременной нагрузкой.
Если TRUNCATE
не является опцией или, как правило, для малых и средних таблиц , существует аналогичная методика с CTE * 1045, модифицирующим данные (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.
Медленнее для больших столов, потому что TRUNCATE
там быстрее. Но может быть быстрее (и проще!) Для небольших столов.
Если у вас вообще нет зависимых объектов, вы можете создать новую таблицу и удалить старую, но вряд ли вы что-то получите по сравнению с этим универсальным подходом.
Для очень больших таблиц, которые не помещаются в доступную оперативную память , создание новой таблицы будет значительно быстрее. Вам придется взвесить это против возможных неприятностей / накладных расходов в зависимости от объектов.