Самый эффективный способ удаления дубликатов - Postgres - PullRequest
0 голосов
/ 11 декабря 2018

Я всегда удалял дубликаты с таким запросом:

delete from test a
using test b 
where a.ctid < b.ctid
and a.col1=b.col1
and a.col2=b.col2
and a.col3=b.col3

Кроме того, я видел, как этот запрос использовался:

DELETE FROM test WHERE test.ctid NOT IN 
(SELECT ctid FROM (
    SELECT DISTINCT ON (col1, col2) *
  FROM test));

И даже этот (повторяется до тех пор, пока вызакончились дубликаты):

delete from test ju where ju.ctid in 
(select ctid from (
select  distinct on (col1, col2) * from test ou
where (select count(*) from test inr
where inr.col1= ou.col1 and inr.col2=ou.col2) > 1

Теперь я столкнулся с таблицей с 5 миллионами строк, в которой есть индексы в столбцах, которые будут соответствовать в предложении where.И теперь мне интересно:

Какой из всех тех методов, которые, по-видимому, делают то же самое, является наиболее эффективным и почему?Я просто запускаю второй, и это занимает более 45 минут, чтобы удалить дубликаты.Мне просто интересно, какой из них будет наиболее эффективным, на случай, если мне придется удалить дубликаты из другой огромной таблицы.Не имеет значения, имеет ли он первичный ключ, вы всегда можете создать его или нет.

1 Ответ

0 голосов
/ 11 декабря 2018

demo: db <> fiddle

Поиск дубликатов может быть легко осуществлен с помощью оконной функции row_number() :

SELECT ctid 
FROM(
    SELECT 
        *, 
        ctid,
        row_number() OVER (PARTITION BY col1, col2, col3 ORDER BY ctid) 
    FROM test
)s
WHERE row_number >= 2

Это упорядочивает связанные строки и добавляет счетчик строк.Поэтому каждая строка с row_number > 1 является дубликатом, который можно удалить:

DELETE 
FROM test
WHERE ctid IN 
(
    SELECT ctid 
    FROM(
        SELECT 
            *, 
            ctid,
            row_number() OVER (PARTITION BY col1, col2, col3 ORDER BY ctid) 
        FROM test
    )s
    WHERE row_number >= 2
)

Я не знаю, быстрее ли это решение, чем ваши попытки, но вы могли бы попробовать.

Более того - как уже говорилось @a_horse_with_no_name - я бы порекомендовал использовать собственный идентификатор вместо ctid для проблем с производительностью.


Редактировать:

Для моих тестовых данных ваша первая версия, кажется, немного быстрее, чем мое решение.Ваша вторая версия кажется медленнее, а ваша третья версия не работает для меня (после исправления ошибок компиляции она не дает результата).

demo: db <> fiddle

...