Как проверить наличие повторов в таблице альтернативным способом
Что проверяют
Это вопрос с подвохом «а если без GROUP BY?». Проверяют, знаете ли вы несколько способов и понимаете ли, где их применять: в базе или в Java-коде. Следом часто спрашивают, почему не стоит тащить всю таблицу в память ради проверки.
Как отвечать
Основной способ GROUP BY ... HAVING COUNT(*) > 1 назовите одной фразой и переходите к альтернативам:
- сравнение счётчиков:
SELECT COUNT(*), COUNT(DISTINCT email) FROM users. Разные числа означают повторы, запрос дешёвый и отвечает на вопрос «есть или нет»; EXISTSс самосоединением:WHERE EXISTS (SELECT 1 FROM users u2 WHERE u2.email = u.email AND u2.id <> u.id). Возвращает сами строки-дубли целиком, а не только значение ключа;- оконная функция:
COUNT(*) OVER (PARTITION BY email)илиROW_NUMBER(). Удобно, когда нужно показать дубли со всеми колонками или оставить одну копию; - уникальный индекс: создание
UNIQUEупадёт, если повторы есть. Заодно это правильная защита на будущее.
В Java проверка уместна, когда данные уже в памяти, например пришли пачкой из файла. HashSet.add возвращает false на повторе, поэтому можно выйти на первом дубле, не проходя весь список. Для отчёта подходит stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())). Обе версии работают за O(n), но только если у класса корректно переопределены equals и hashCode.
В Spring Data запрос с HAVING или EXISTS оформляется через @Query, а результат лучше вернуть числом или проекцией, не загружая сущности.
Где спотыкаются
Выгружают таблицу через findAll() и ищут повторы в HashSet. На миллионе строк это лишняя память и сетевой трафик, хотя база ответит на тот же вопрос одним запросом.
Кладут в HashSet сущности без equals и hashCode. Сравнение идёт по ссылке, два одинаковых объекта считаются разными, и метод честно отвечает «дублей нет».
Забывают про регистр и пробелы. Ivan@mail.ru и ivan@mail.ru для базы разные строки, так что сравнивать нужно нормализованное значение. Иначе любой из способов найдёт меньше повторов, чем есть на самом деле.