По моему опыту (и как показано во многих тестах), NOT IN
как показал @gsiems, он довольно медленный и масштабируется ужасно. Обратное, IN
как правило, быстрее (где вы можете переформулировать таким образом, как в этом случае), но этот запрос с EXISTS
(делая именно то, что вы просили) должен быть еще быстрее - с большими таблицами на порядки :
DELETE FROM questions_tags q
WHERE EXISTS (
SELECT FROM questions_tags q1
WHERE q1.ctid < q.ctid
AND q1.question_id = q.question_id
AND q1.tag_id = q.tag_id
);
Удаляет каждую строку , в которой другой ряд с тем же (tag_id, question_id)
и меньше ctid
существует . (Эффективно сохраняет первый экземпляр в соответствии с физическим порядком кортежей.) При использовании ctid
в отсутствие лучшей альтернативы ваша таблица, похоже, не имеет PK или какого-либо другого уникального (набора) столбцов.
ctid
является внутренним идентификатором кортежа, присутствующим в каждой строке и обязательно уникальным. Дальнейшее чтение:
Тестовое задание
Я выполнил тестовый пример с этой таблицей, соответствующей вашему вопросу и 100k строк:
CREATE TABLE questions_tags(
question_id integer NOT NULL
, tag_id integer NOT NULL
);
INSERT INTO questions_tags (question_id, tag_id)
SELECT (random()* 100)::int, (random()* 100)::int
FROM generate_series(1, 100000);
ANALYZE questions_tags;
Индексы не помогают в этом случае.
Результаты
NOT IN
Время ожидания SQLfiddle истекло.
Пробовал то же самое локально, но я тоже отменил через несколько минут.
EXISTS
Заканчивается через полсекунды в этом SQLfiddle .
альтернативы
Если вы собираетесь удалить большинство строк , вам будет проще выбрать выживших в другую таблицу, отбросить оригинал и переименовать таблицу выживших. Осторожно, это имеет значение, если у вас есть вид или внешние ключи (или другие зависимости), определенные на оригинале.
Если у вас есть зависимости и вы хотите их сохранить, вы можете:
- Отбросьте все внешние ключи и индексы - для производительности.
SELECT
выжившие к временному столу.
TRUNCATE
оригинал.
- ПЕРЕУСТАНОВКИ
INSERT
выжившие.
- Переиндексирует
CREATE
и внешние ключи. Представления могут просто остаться, они не влияют на производительность. Больше здесь или здесь .