Замість того, щоб створювати нову таблицю, ви також можете повторно вставити унікальні рядки в одну таблицю після її обрізання. Робіть все за одну транзакцію . За бажанням ви можете автоматично скинути тимчасову таблицю в кінці транзакції за допомогою ON COMMIT DROP
. Дивись нижче.
Цей підхід корисний лише там, де є багато рядків для видалення з усієї таблиці. Для кількох дублікатів використовуйте звичайний текст DELETE
.
Ви згадали мільйони рядків. Щоб зробити операцію швидкою , потрібно виділити достатньо тимчасових буферів для сеансу. Параметр потрібно відкоригувати перед тим, як будь-який тимчасовий буфер буде використаний у вашому поточному сеансі. Дізнайтеся розмір вашого столу:
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 (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
там швидше. Але це може бути швидше (і простіше!) Для невеликих столиків.
Якщо у вас взагалі немає залежних об’єктів, ви можете створити нову таблицю та видалити стару, але навряд чи ви отримаєте щось за цей універсальний підхід.
Для дуже великих таблиць, які не вписуються в наявну оперативну пам’ять , створення нової таблиці буде значно швидшим. Вам доведеться зважити це з можливими проблемами / накладними витратами залежно від об’єктів.