Как наличие повторяющихся строк влияет на результат объединения двух запросов через UNION?

Как наличие повторяющихся строк влияет на результат объединения двух запросов через UNION?

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

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

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

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

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

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

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

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

Неверный выбор операции может исказить смысл данных. Например, при подсчёте количества событий нельзя незаметно заменить UNION ALL на UNION, потому что удаление дубликатов уменьшит итоговое количество строк.

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

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

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

SELECT 1 AS номер UNION SELECT 1 AS номер;

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

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

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

Порядок строк результатом UNION не гарантируется без отдельной сортировки. Устранение дубликатов также не означает выбор одной «первой» строки среди различающихся строк: удаляются только полностью совпадающие строки.

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

В системе формируется отчёт о всех операциях, поступивших из двух независимых очередей. Один и тот же идентификатор операции может присутствовать в обеих очередях из-за повторной доставки, но для аудита требуется сохранить каждое полученное событие.

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

Выбирают UNION ALL, потому что предметная область считает каждую запись отдельным событием. Дополнительная обработка, если она нужна, выполняется явно по бизнес-правилу: например, повтор доставки можно отличить по идентификатору события и времени. В результате отчёт не теряет факты из-за неявного устранения строк.

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

  1. Чем UNION отличается от DISTINCT, применённого к каждому исходному запросу отдельно?

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

  1. Можно ли считать UNION безопасной заменой UNION ALL, если в каждом источнике нет повторов?

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

  1. Почему UNION может быть заметно медленнее UNION ALL на больших результатах?

UNION ALL может последовательно вернуть строки обоих запросов без глобального сравнения. UNION должен обнаружить одинаковые строки во всём объединённом наборе, поэтому СУБД может сортировать результат или строить хеш-структуру; это требует дополнительного времени и памяти. Конкретный план зависит от СУБД, объёма данных и доступных ресурсов, поэтому окончательное решение следует проверять по плану выполнения и фактическим измерениям.