PostgreSQL: удаление повторяющихся строк на основе совпадающих хешей md5

У меня есть таблица, заполненная данными, полученными из Интернета. После добавления новых данных в таблицу я хочу удалить дубликаты, если в определенные столбцы не было внесено никаких изменений.

Я попробовал следующий запрос вместе с различными способами ссылки на хэш md5 и преобразование столбца1 в текст:

DELETE FROM
    my_table a
        USING my_table b
WHERE
    a.pk < b.pk
    AND a.md5(column1) = b.md5(column1);

и получите следующую ошибку:

ERROR: column reference "column1" is ambiguous 
LINE 6: AND a.md5(column1) = b.md5(column1); 
                  ^ 
SQL state: 42702 Character: 99

Попробуйте: AND md5(a.column1) = md5(b.column1);

Soren 15.03.2024 10:40

@Сорен большое спасибо, проблема решена, спасибо за столь быстрый ответ

Nathan McIntosh 15.03.2024 12:16

Попробуйте a.column1=b.column1 — это будет быстрее и надежнее, если вы позволите Postgres разобраться в деталях.

Zegarek 15.03.2024 12:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Не делайте дедупликацию на основе md5(), просто используйте =

Пусть Postgres выяснит, имеет ли он вообще выгоду от хеширования, и если да, то какой должна быть оптимальная функция хеширования. Вам легче объявлять, Postgres легче оптимизировать и выполнять. SQL задуман как декларативный — укажите, что вы хотите, а не как именно это должно быть сделано.

Таким образом вы также избежите потенциально неверных результатов — md5 используется просто для простоты, но долгое время считался ненадежным. Редко, но не невозможно, чтобы ваши значения были совершенно разными, но имели один и тот же md5, поэтому вы можете получить незаслуженное удаление.

Если Postgres обнаружит, что значения слишком длинные для эффективного сравнения с простым =, он незаметно изменит равенство значений на равенство хеш-значений, используя хэш-функцию по своему выбору:

explain analyze verbose
DELETE FROM my_table a
USING my_table b
WHERE a.pk < b.pk
AND a.column1 = b.column1
returning *;
ПЛАН ЗАПРОСА Удалить в public.my_table a (стоимость = 3758,00..10978,49 строк = 7480, ширина = 650) (фактическое время = 26,669..68,048 строк = 1858 циклов = 1) ...   -> Хэш-соединение (стоимость = 3758,00..10978,49 строк = 7480, ширина = 650) (фактическое время = 26,642..64,441 строк = 1985 циклов = 1) ...         Хэш-условие: (a.column1 = b.column1) ...         -> Хэш (стоимость = 1867,00..1867,00 строк = 20000, ширина = 644) (фактическое время = 26,444..26,445 строк = 20000 циклов = 1) ... Время выполнения: 68,541 мс

Обратите внимание, как версия с md5 влияет на такое же количество строк, только в 4 раза медленнее: демо

explain analyze verbose
DELETE FROM my_table a
USING my_table b
WHERE a.pk < b.pk
AND md5(a.column1) = md5(b.column1)
returning *;
Удалить в public.my_table a (стоимость = 18078,54..63328,54 строк = 666667 ширина = 650) (фактическое время = 215,633..249,269 строк = 1858 циклов = 1)   Вывод: a.pk, a.column1, b.pk, b.column1   -> Объединение слиянием (стоимость = 18078.54..63328.54 строк = 666667 ширина = 650) (фактическое время = 215.603..246.022 строк = 1985 циклов = 1) ... Время выполнения: 252,893 мс

В качестве бонуса, если будущие версии Postgres будут улучшены с точки зрения хэш-операций, вы получите это бесплатно с =, без необходимости повторно обращаться и обновлять какой-либо код.

Отличное спасибо за ответ и демо. У меня есть база данных шириной 75 столбцов, и я хочу сохранить новую запись, если какая-либо из 8 ключевых записей изменилась. Будет ли это масштабироваться линейным образом?

Nathan McIntosh 17.03.2024 09:31

Мне нужен пример описанного вами сравнения/дедупликации (я не совсем понял идею ни одной из 8 ключевых записей в этом контексте), но да, вы можете ожидать, что это будет линейно масштабироваться.

Zegarek 17.03.2024 10:27

Другие вопросы по теме