Вместо создания новой таблицы вы также можете повторно вставить уникальные строки в ту же таблицу после ее усечения. Сделайте все за одну транзакцию . При желании вы можете автоматически удалить временную таблицу в конце транзакции с помощью ON COMMIT DROP
. Увидеть ниже.
Этот подход полезен только в том случае, если нужно удалить много строк по всей таблице. Для нескольких дубликатов используйте простой DELETE
.
Вы упомянули миллионы строк. Чтобы сделать операцию быстрой, вам нужно выделить достаточно временных буферов для сеанса. Этот параметр необходимо изменить до того, как в текущем сеансе будет использоваться какой-либо временный буфер. Узнайте размер вашего стола:
SELECT pg_size_pretty(pg_relation_size('tbl'));
Установите temp_buffers
соответственно. Обильно округлите, потому что для представления в памяти требуется немного больше ОЗУ.
SET temp_buffers = 200MB;
BEGIN;
CREATE TEMPORARY TABLE t_tmp AS
SELECT DISTINCT * FROM tbl;
TRUNCATE tbl;
INSERT INTO tbl
SELECT * FROM t_tmp;
COMMIT;
Этот метод может быть лучше создания новой таблицы, если существуют зависимые объекты. Представления, индексы, внешние ключи или другие объекты, ссылающиеся на таблицу. TRUNCATE
заставляет вас начать с чистого листа в любом случае (новый файл в фоновом режиме) и много быстрее, чем DELETE FROM tbl
с большими таблицами (на DELETE
самом деле может быть быстрее с маленькими таблицами).
Для больших столов регулярно быстрее отбрасывать индексы и внешние ключи, заполнять таблицу и воссоздавать эти объекты. Что касается ограничений fk, вы, конечно, должны быть уверены, что новые данные действительны, иначе вы столкнетесь с исключением при попытке создать fk.
Обратите внимание, что TRUNCATE
требуется более агрессивная блокировка, чем DELETE
. Это может быть проблемой для таблиц с большой одновременной нагрузкой.
Если TRUNCATE
это не вариант или, как правило, для небольших и средних таблиц существует аналогичная техника с CTE, изменяющим данные (Postgres 9.1 +):
WITH del AS (DELETE FROM tbl RETURNING *)
INSERT INTO tbl
SELECT DISTINCT * FROM del;
Медленнее для больших столов, потому что TRUNCATE
там быстрее. Но может быть быстрее (и проще!) Для небольших столов.
Если у вас вообще нет зависимых объектов, вы можете создать новую таблицу и удалить старую, но вы вряд ли получите что-либо от этого универсального подхода.
Для очень больших таблиц, которые не помещаются в доступную оперативную память , создание новой таблицы будет значительно быстрее. Вам придется взвесить это с возможными проблемами / накладными расходами с зависимыми объектами.