В CTE, объединяющем два источника, что изменится при замене UNION ALL на UNION, если одна и та же строка пр...

В CTE, объединяющем два источника, что изменится при замене UNION ALL на UNION, если одна и та же строка приходит из обеих ветвей?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

UNION ALL сохранит обе строки, а UNION удалит повторяющуюся строку после объединения результатов обеих ветвей. Поэтому последующая агрегация, подсчёт строк или соединение с другими таблицами могут дать разные результаты.

Дубликаты определяются по всем столбцам результирующей строки, а не по источнику, из которого она пришла.

Исторический контекст

Операции над множествами происходят из реляционной алгебры, где повторяющиеся элементы не имеют значения. Однако SQL обычно работает с мультимножествами: одинаковые строки сохраняются, поскольку повторы могут отражать количество фактов, событий или связей.

Поэтому SQL разделяет два режима. UNION реализует объединение с устранением повторов, а UNION ALL сохраняет мультимножество и обычно требует меньше вычислений.

Постановка проблемы

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

Особенно заметно это после группировки: при UNION ALL количество повторений влияет на COUNT(*), суммы и другие агрегаты. При UNION одинаковые строки сначала схлопываются, поэтому такие показатели могут стать меньше.

Подробное решение

Сначала SQL вычисляет каждую ветвь, затем объединяет их. UNION ALL просто concatenates результаты, сохраняя каждую строку. UNION выполняет устранение дубликатов по полной строке результата, концептуально аналогичное применению DISTINCT к объединённому набору.

Минимальный пример:

WITH all_rows AS ( SELECT id FROM source_a UNION ALL SELECT id FROM source_b ) SELECT id, COUNT(*) AS occurrences FROM all_rows GROUP BY id;

Если значение id присутствует в обоих источниках, результат содержит две строки до группировки, и occurrences равен двум. При замене UNION ALL на UNION останется одна строка, и счётчик станет равен одному.

Сравнение выполняется по всем столбцам, выбранным обеими ветвями, в их результирующем порядке. Если хотя бы один столбец отличается, строки не считаются дубликатами. Значения NULL участвуют в проверке различимости строк как значения, не позволяющие сохранить две полностью неразличимые строки в результате UNION.

У UNION есть цена: для устранения повторов СУБД может использовать сортировку или хеширование, расходуя память и время. UNION ALL обычно быстрее, но ответственность за корректность повторов полностью лежит на разработчике.

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

Ситуация из практики

В отчёте объединялись записи о платежах из основной и архивной систем. Разработчик выбрал UNION, потому что визуально одинаковые платежи казались дублями. После этого сумма платежей уменьшилась: две системы хранили независимые операции с одинаковыми клиентом, датой и суммой.

Рассматривались два варианта. UNION был простым, но ошибочно удалял реальные повторные операции. UNION ALL сохранял данные, однако мог передать настоящие дубли миграции дальше по запросу. Дедупликация по идентификатору операции была точнее, но требовала определить источник истины и правило выбора записи.

Выбрали UNION ALL, а затем отдельную дедупликацию по стабильному идентификатору операции. Это сохранило количество реальных платежей и позволило контролируемо устранить технические повторы. Результат оказался корректнее, чем безусловное сравнение всей строки.

Что кандидаты часто упускают

1. Удаляет ли UNION дубликаты внутри каждой ветви отдельно или только после объединения?

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

2. Что произойдёт, если одинаковые идентификаторы имеют разные значения в других выбранных столбцах?

Строки не будут дубликатами, если отличается хотя бы один столбец результата. Например, строки с одним id, но разными статусами сохранятся обе. UNION не знает бизнес-ключ и не удаляет строки только по одному выбранному идентификатору.

3. Всегда ли UNION безопаснее UNION ALL с точки зрения качества данных?

Нет. UNION безопаснее только тогда, когда повторяющиеся полные строки действительно семантически означают один объект. Для событий, транзакций и фактов повтор может быть значимым. Выбор оператора должен основываться на смысле строк и правилах идентификации, а не только на желании убрать визуальные дубли.