SQL UNION против UNION ALL: Различия, примеры и проверка производительности
Разница между ними — одно слово, но неправильный выбор может незаметно дать вам неправильную сумму. Посмотрите оба на реальных данных, изучите общие правила и прочитайте, что произошло, когда мы рассчитали время их выполнения по миллиону строк.
UNIONобъединяет результаты и удаляет повторяющиеся строки.UNION ALLсохраняет каждую строку.- Расходы на дедупликацию работают, поэтому
UNION ALLобычно вычисляется быстрее. - Использование
UNIONпередSUMможет незаметно удалить реальные значения и дать неправильный ответ. - По умолчанию —
UNION ALL, если вы специально не хотите удалять дубликаты.
Оба оператора складывают результаты двух запросов друг на друга, поэтому SQL UNION vs UNION ALL может показаться второстепенным выбором. Это не. Одно лишнее слово меняет как ваш результат, так и то, насколько усердно приходится работать базе данных.
Мы выполнили каждый запрос здесь, в SQLite 3.50, и показанные результаты и время получены из этих запусков. Основное поведение — стандартный SQL для основных баз данных. Однако время будет отличаться в зависимости от вашей базы данных, данных и оборудования, поэтому воспринимайте наше как иллюстрацию.
Короткий ответ
UNION объединяет два набора результатов и возвращает только разные строки. UNION ALL объединяет их и возвращает все, включая дубликаты. В этом вся разница, и оставшаяся часть статьи посвящена тому, почему это важно.
UNION против UNION ALL бок о бок
| Аспект | СОЮЗ | СОЮЗ ВСЕХ |
|---|---|---|
| Повторяющиеся строки | Удален | Сохранено |
| Дополнительная работа | Необходимо найти дубликаты | Нет |
| Обычная скорость | Медленнее | Быстрее |
| Строки возвращены | То же или меньше | Все они |
| Безопасно перед SUM или COUNT? | Часто нет | Да |
| Лучшее для | Уникальные списки | Объединение данных, журналов, итогов |
Пример данных
Представьте себе магазин, который хранит онлайн- и офлайн-заказы в отдельных таблицах. Обратите внимание, что у Аши есть два одинаковых онлайн-заказа и один идентичный заказ в магазине.
CREATE TABLE online_orders (customer TEXT, total INT);
CREATE TABLE store_orders (customer TEXT, total INT);
INSERT INTO online_orders VALUES ('Asha',100), ('Ben',200), ('Asha',100);
INSERT INTO store_orders VALUES ('Asha',100), ('Dev',300);
Посмотрите разницу
SELECT customer, total FROM online_orders
UNION
SELECT customer, total FROM store_orders;
-- Asha | 100
-- Ben | 200
-- Dev | 300
SELECT customer, total FROM online_orders
UNION ALL
SELECT customer, total FROM store_orders;
-- Asha | 100
-- Ben | 200
-- Asha | 100
-- Asha | 100
-- Dev | 300
Пять входных строк стали тремя с UNION, а все пять остались с UNION ALL. Две вещи, на которые следует обратить внимание:
UNIONудалил дубликаты из всего результата, включая те, которые находятся в первой таблице. Это не только сравнение между таблицами.- Строка считается дубликатом только в том случае, если каждый выбранный столбец совпадает.
Если вам действительно нужен отдельный список, UNION будет совершенно правильным. Это дает каждому клиенту, совершившему покупку через любой канал:
SELECT customer FROM online_orders
UNION
SELECT customer FROM store_orders;
-- Asha
-- Ben
-- Dev
Тотальная неправильная ошибка
Вот почему выбор действительно имеет значение. Предположим, вам нужен общий доход. Сумма заказов выше составляет 800. Посмотрите, что дает каждый оператор:
SELECT SUM(total) FROM (
SELECT total FROM online_orders
UNION
SELECT total FROM store_orders
);
-- 600
SELECT SUM(total) FROM (
SELECT total FROM online_orders
UNION ALL
SELECT total FROM store_orders
);
-- 800
Версия UNION ошибочна на 200. Поскольку мы выбрали только столбец total, три отдельных заказа на 100 рупий выглядели как дубликаты и схлопнулись в один. Сообщения об ошибке нет, а число 600 выглядит вполне правдоподобным. Подобные тихие ошибки могут оставаться в финансовом отчете месяцами.
Совет. Две одинаковые строки могут быть двумя реальными событиями. Прежде чем использовать UNION, спросите, означают ли одинаковые строки один и тот же факт, записанный дважды, или два разных факта. Для продаж, платежей и записей журнала обычно это второй вариант.
Правила, которым должны следовать оба
Оба оператора имеют одинаковые требования:
- Каждый
SELECTдолжен возвращать то же количество столбцов. - Столбцы сопоставляются по позиции, а не по имени, поэтому сохраняйте их в том же порядке.
- Типы данных в каждой позиции должны быть совместимы.
- Имена столбцов результатов берутся из first
SELECT. ORDER BYидет в самом конце и применяется ко всему результату.
Нарушение первого правила приводит к ошибке. Вот сообщение от SQLite:
SELECT customer, total FROM online_orders
UNION
SELECT customer FROM store_orders;
-- SELECTs to the left and right of UNION do not have
-- the same number of result columns
Второе правило более опасно, поскольку оно может не выполниться без ошибки. Если вы поменяете местами два столбца одного и того же типа, например first_name и last_name, запрос выполнится, и данные будут получены неверными. SQLite также небрежно относится к типам, в то время как такие базы данных, как PostgreSQL, более строги и могут требовать явного указания CAST.
Пометьте источник
Очень практичный трюк — добавить постоянный столбец, показывающий, откуда взялась каждая строка. Поскольку метки различаются, строки из разных таблиц больше нельзя рассматривать как дубликаты друг друга.
SELECT customer, total, 'online' AS channel FROM online_orders
UNION ALL
SELECT customer, total, 'store' FROM store_orders
ORDER BY customer, channel;
-- Asha | 100 | online
-- Asha | 100 | online
-- Asha | 100 | store
-- Ben | 200 | online
-- Dev | 300 | store
Как только вашим данным будет присвоена метка, вы сможете сгруппировать их, чтобы составить отчет о продажах по каналам, используя GROUP BY. Если вам нужно объединить несколько шагов, оберните объединение в CTE, чтобы оно было читабельным.
Производительность: что произошло в нашем тесте
Чтобы удалить дубликаты, база данных должна сравнить строки, обычно путем их сортировки или хеширования. UNION ALL может пропустить этот шаг. Мы создали две таблицы по 500 000 строк в каждой, содержащие случайные числа от 0 до 50 000, поэтому дубликатов было много. Мы запускали каждый запрос несколько раз и фиксировали лучшее время.
Сначала мы подсчитали результаты, чтобы время, потраченное на отправку строк обратно в нашу программу, не влияло на сравнение:
| Запрос, завернутый в COUNT(*) | Строки | Лучшее время |
|---|---|---|
| СОЮЗ | 50,001 | 261 мс |
| СОЮЗ ВСЕХ | 1,000,000 | Менее 1 мс |
Огромный разрыв отчасти объясняется тем, что SQLite может подсчитать это значение, не читая каждую строку, поэтому, пожалуйста, не читайте это как «в тысячи раз быстрее». Тем не менее, это отражает основную идею: UNION должен был проделать реальную работу, а UNION ALL — нет.
Затем мы извлекли все строки в Python, и результат изменился:
| Запрос, получение всех строк | Строки возвращены | Лучшее время |
|---|---|---|
| СОЮЗ | 50,001 | 277 мс |
| СОЮЗ ВСЕХ | 1,000,000 | 392 мс |
Здесь UNION ALL заняло больше времени, поскольку выдало в двадцать раз больше строк. Дедупликация не является причиной замедления процесса. Обработка миллиона строк была. Итак, честное правило заключается в том, что UNION ALL дешевле вычислить в базе данных, но размер результата тоже имеет значение. Многие онлайн-диаграммы сводят это к «UNION ALL всегда быстрее», и наш тест показывает, почему это не так просто.
Не делайте выбор только по скорости. Сначала выберите оператора, дающего правильный ответ, а затем настройтесь. Если запрос выполняется медленно, прочитайте наше руководство по оптимизации SQL-запросов.
Когда использовать каждый
Используйте UNION ALL, когда:
- Вы объединяете данные из похожих таблиц, например ежемесячных разделов.
- После этого вы подсчитаете итоги или подсчеты.
- Вы знаете, что входные данные не могут перекрываться.
- Дубликаты имеют смысл, например, в журналах или записях аудита.
Используйте UNION, когда:
- Вам нужен уникальный список, например каждый адрес электронной почты в двух системах.
- Перекрывающиеся источники неоднократно содержат один и тот же факт.
Считайте UNION ALL значением по умолчанию и используйте UNION сознательно. Добавление предложения WHERE в каждую ветку для ранней фильтрации помогает в обоих случаях.
ПЕРЕСЕЧЕТЬ и ИСКЛЮЧИТЬ
Два связанных оператора множества отвечают на разные вопросы. Оба следуют одним и тем же правилам столбцов:
SELECT customer FROM online_orders
INTERSECT
SELECT customer FROM store_orders;
-- Asha (bought in both channels)
SELECT customer FROM online_orders
EXCEPT
SELECT customer FROM store_orders;
-- Ben (online only)
Oracle традиционно использует MINUS, а не EXCEPT, и поддержка этих операторов немного различается в зависимости от базы данных и версии.
СОЮЗ против ПРИСОЕДИНЯЙТЕСЬ
Их часто путают, но они объединяют данные в разных направлениях:
| Операция | Направление | Результат |
|---|---|---|
| СОЮЗ | Вертикальный | Добавляет больше строк |
| ПРИСОЕДИНЯЙТЕСЬ | Горизонтальный | Добавляет больше столбцов |
Распространенные ошибки
- Использование UNION по привычке. Это может стоить вам скорости или удалять допустимые строки.
- Выбрано слишком мало столбцов. Если не указать идентификатор, отдельные строки будут выглядеть одинаково.
- Несоответствующий порядок столбцов. Значения могут оказаться в неправильном столбце без каких-либо ошибок.
- Добавление ORDER BY в каждую ветку. Сортировка один раз, в конце.
- Использование UNION для исправления неправильного соединения. Если из-за соединения появляются дубликаты, исправьте соединение.
- При условии порядка результатов. Без
ORDER BYпорядок строк не гарантируется ни для одного оператора.
Итоги
Каждый раз задавайте один вопрос: идентичные строки — это один и тот же факт или отдельные факты? Если они разделены или перекрытие невозможно, используйте UNION ALL. Если вам нужен уникальный список, используйте UNION. Чтобы проверить свои собственные отчеты, найдите в своем коде UNION рядом с SUM или COUNT и убедитесь, что эти суммы действительно верны.
Часто задаваемые вопросы
В чем разница между UNION и UNION ALL?
UNION объединяет два набора результатов и удаляет повторяющиеся строки. UNION ALL объединяет их и сохраняет каждую строку, включая дубликаты.
Что быстрее, UNION или UNION ALL?
UNION ALL обычно дешевле вычислить, поскольку он не проверяет наличие дубликатов. Как показал наш тест, возврат гораздо большего результата в целом может занять больше времени.
Удаляет ли UNION дубликаты в одной таблице?
Да. Он удаляет дубликаты во всем объединенном результате, включая идентичные строки, взятые из одной таблицы.
Должны ли имена столбцов совпадать в UNION?
Нет. Столбцы сопоставляются по положению, а в результате используются имена из первого SELECT. Количество столбцов должно совпадать, а типы должны быть совместимыми.
Могу ли я использовать ORDER BY с UNION?
Да, но поместите один ORDER BY в самом конце оператора. Он сортирует весь объединенный результат, а не одну ветвь.
Продолжайте учиться
Нужна помощь с тестированием, WordPress или SEO?
Мы помогаем командам выпускать лучшее программное обеспечение и развивать свои сайты. Расскажите нам, над чем вы работаете, и мы предложим четкий следующий шаг.
Больше руководств по тестирование, искусственный интеллект и современные разработки
Понравилась эта статья? Выберите тему и сразу приступайте к нашим новейшим руководствам.
Объяснение галлюцинаций искусственного интеллекта: почему языковые модели все выдумывают и как их уменьшить
Галлюцинации ИИ объяснили: что это такое, почему языковые модели их создают, распространенные типы, как уменьшить их с помощью заземления и подсказо…
Читать статью →DevOpsОбъяснение переменных среды: файлы .env, секреты и правильно выполненная конфигурация
Переменные среды объясняются на примерах Python, которые мы запускали: их чтение и установка, почему каждое значение является строкой, файлы .env, н…
Читать статью →Разработка ПООбъяснение ограничения скорости API: алгоритмы, заголовки и обработка ошибок 429
Ограничение скорости API объясняется с помощью проведенного нами моделирования: сегмент токенов, фиксированное окно, скользящее окно, 429 ответов, з…
Читать статью →Автоматизация тестированияИздевательство в Python: unittest.mock, патч и ошибки, из-за которых тесты лгут
Издевательство на Python с помощью unittest.mock, протестировано: Mock и return_value, Side_effect, исправление использования имени, спецификация и …
Читать статью →Тестирование ПООбъяснение покрытия кода: покрытие линий или ветвей и что на самом деле означает 100%
Покрытие кода объяснено с помощью реального запуска покрытия.py: покрытие строк, ветвей и условий, чтение отчета, почему 100%-ное покрытие все еще м…
Читать статью →Базы данных и SQLDELETE, TRUNCATE и DROP в SQL: различия, откат и когда использовать каждый из них
Объяснение DELETE, TRUNCATE и DROP на примере протестированного SQL: что каждый из них удаляет, откат, триггеры, сброс идентификаторов, скорость и ч…
Читать статью →Базы данных и SQLОбъяснение представлений SQL: создавайте, используйте и избегайте ловушек, с примерами
Представления SQL, объясненные с помощью запросов, которые мы выполняли: создание представления, результаты в реальном времени, скрытие столбцов, пр…
Читать статью →Разработка ПОИнтерфейс TypeScript и тип: реальные различия, протестированные с помощью компилятора
Интерфейс TypeScript против типа, проверенный реальным компилятором: что могут делать оба, что может делать только один, слияние объявлений, расшире…
Читать статью →Разработка ПООбъяснение Python *args и **kwargs: гибкие функции с понятными примерами
Python *args и **kwargs, объясненные с помощью кода, который мы запускали: упаковка и распаковка, порядок параметров, аргументы только по ключевым с…
Читать статью →Разработка ПОЛямбда-функции Python: синтаксис, реальное использование и когда их не следует использовать
Лямбда-функции Python, объясненные с помощью кода, который мы запускали: синтаксис, сортировка с помощью ключа, карты и фильтра, замыкания, ловушка …
Читать статью →Искусственный интеллектЧто такое ИИ-агенты? Как они работают: можно запустить простой цикл агента
Что такое агенты ИИ? Простое руководство по циклу агента, инструментам, памяти и ограничениям, с небольшим циклом Python, который мы запустили, реал…
Читать статью →DevOpsМониторинг и наблюдаемость: реальная разница с журналами, метриками и трассировками
Объяснение мониторинга и наблюдаемости: известные и неизвестные сбои, журналы, метрики и трассировки, пошаговое руководство по инцидентам при оформл…
Читать статью →DevOpsDocker Volumes против Bind Mounts: правильное сохранение данных контейнера
Объяснение томов Docker и монтирования привязки: почему исчезают данные контейнера, именованные тома, монтирование привязки, tmpfs, примеры создания…
Читать статью →Автоматизация тестированияTDD против BDD: ключевые различия, одна функция, созданная для обоих способов, и когда использовать каждый
TDD и BDD объясняются с помощью одной функции скидки, созданной в обоих направлениях: красно-зеленый рефакторинг с кодом, который мы запускали, сцен…
Читать статью →Тестирование ПОПользовательское приемочное тестирование (UAT): процесс, контрольный список и реальные примеры
Приемочное тестирование пользователей объяснило: кто его проводит, чем оно отличается от контроля качества, семиэтапный процесс, шаблон тестового сц…
Читать статью →Базы данных и SQLОбъяснение значений NULL в SQL: IS NULL, COALESCE, NULLIF и ловушки, которых следует избегать
Значения SQL NULL объяснены с помощью запросов, которые мы выполнили: трехзначная логика, IS NULL, COALESCE, NULLIF, как агрегаты, соединения и сорт…
Читать статью →Базы данных и SQLОператор SQL CASE WHEN: синтаксис, реальные примеры и распространенные ошибки
SQL CASE WHEN объяснен с помощью запросов, которые мы выполняли: простые формы и формы для поиска, порядок условий, повороты с помощью SUM, трюки CO…
Читать статью →Разработка ПОЧто такое JWT? Веб-токены JSON, объясненные на рабочем примере
Что такое JWT? Объяснение JSON Web Tokens: три части: токен, созданный и измененный в коде, который мы запускали, JWT и сеансы, хранилище, токены об…
Читать статью →Разработка ПООбъяснение цикла событий JavaScript: стек вызовов, микрозадачи и таймеры с примерами
Цикл событий JavaScript объясняется с помощью кода, который мы запускали: стек вызовов, очереди задач и микрозадач, почему setTimeout 0 не является …
Читать статью →Разработка ПОГенераторы Python и объяснение доходности: экономьте память с помощью реальных примеров
Генераторы Python и доходность, объясненные с помощью кода, который мы запускали: как они приостанавливаются и возобновляются, измеряют экономию пам…
Читать статью →Искусственный интеллектЧто такое вложения? Простое объяснение векторов и косинусного сходства
Что такое вложения? Простое руководство по векторам, косинусному подобию и семантическому поиску с небольшим примером, который мы использовали, общи…
Читать статью →DevOpsСине-зеленое и канареечное развертывание: различия, компромиссы и как выбрать
Объяснение сине-зеленого и канареечного развертывания: как каждый из них работает, стоимость, риски и откат, стабильное группирование пользователей,…
Читать статью →Автоматизация тестированияНенадежные тесты: что их вызывает и как их исправить навсегда
Ненадежные тесты объясняются на демонстрациях, которые мы запускали: основные причины, способы подтверждения и диагностики, правильные исправления в…
Читать статью →Тестирование ПОНагрузочное тестирование и стресс-тестирование: различия, метрики и примеры k6
Объяснение нагрузочного и стресс-тестирования: что доказывает каждое из них, тесты на всплески и выдержки, важные метрики, почему средние значения в…
Читать статью →Тестирование ПОТестовый пример и тестовый сценарий: ключевые различия, примеры и когда использовать каждый
Объяснение тестового случая и тестового сценария: четкие определения, параллельная таблица, одна функция сброса пароля, взятая из сценариев в случаи…
Читать статью →Базы данных и SQLОптимизация SQL-запросов: чтение планов выполнения и исправление медленных запросов с указанием времени
Оптимизация SQL-запросов проверена на миллионе строк: читайте планы выполнения, добавляйте правильные индексы, исправляйте неразмещаемые фильтры, ис…
Читать статью →Базы данных и SQLSQL UNION против UNION ALL: различия, примеры и проверка производительности
SQL UNION и UNION ALL объяснены с помощью запросов, которые мы выполнили: дубликаты, правила, которым следуют оба, реальная ошибка данных, измеренна…
Читать статью →Разработка ПОУчебное пособие по API JavaScript Fetch: GET, POST, обработка ошибок и тайм-ауты
Учебное пособие по API JavaScript Fetch, протестированное на локальном сервере: GET и POST, почему не выдается ошибка 404, многоразовый помощник, ст…
Читать статью →Разработка ПООбработка файлов Python: чтение, запись, CSV, JSON и pathlib с примерами
Обработка файлов Python объясняется с помощью кода, который мы запускали: открытые режимы, чтение больших файлов, CSV, JSON, pathlib, двоичные файлы…
Читать статью →Разработка ПОGit merge vs rebase: отличия, примеры и когда что использовать
Git merge vs rebase с реальным выводом log, сравнительной таблицей, золотым правилом rebase и безопасным рабочим процессом для команды.
Читать статью →Разработка ПОГенераторы списков в Python: синтаксис, примеры и когда их избегать
Генераторы списков в Python: синтаксис, фильтры, if-else, вложенные циклы, измеренное время и случаи, когда обычный цикл for лучше.
Читать статью →Базы данных и SQLSQL JOIN: объяснение с примерами (Inner, Left, Right, Full)
Разберите SQL JOIN шаг за шагом на примерах таблиц и запросов: INNER, LEFT, RIGHT, FULL, CROSS и SELF, а также частые ошибки и советы по производите…
Читать статью →