Вместо создания новой таблицы вы также можете повторно вставить уникальные строки в ту же таблицу после ее усечения. Сделайте все за одну транзакцию . При желании вы можете автоматически удалить временную таблицу в конце транзакции с помощью 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 там быстрее. Но может быть быстрее (и проще!) Для небольших столов.
Если у вас вообще нет зависимых объектов, вы можете создать новую таблицу и удалить старую, но вы вряд ли получите что-либо от этого универсального подхода.
Для очень больших таблиц, которые не помещаются в доступную оперативную память , создание новой таблицы будет значительно быстрее. Вам придется взвесить это с возможными проблемами / накладными расходами с зависимыми объектами.