Подтвердить что ты не робот

SQL Performance UNION против OR

Я просто прочитал часть статьи по оптимизации и разделился на следующее утверждение:

При использовании операторов SQL replace с помощью OR с UNION:

select username from users where company = ‘bbc’ or company = ‘itv’;

в

select username from users where company = ‘bbc’ union
select username from users where company = ‘itv’;

Из быстрого EXPLAIN:

Использование OR:

enter image description here

Использование UNION:

enter image description here

Разве это не означает, что UNION выполняет двойную работу?

Хотя я ценю, что UNION может быть более эффективным для определенных RDBMS и определенных схем таблиц, это не является категорически истинным, как предложения автора.

Вопрос

Я не прав?

4b9b3361

Ответ 1

Либо прочитанная вами статья использовала плохой пример, либо неверно истолковала их точку.

select username from users where company = 'bbc' or company = 'itv';

Это эквивалентно:

select username from users where company IN ('bbc', 'itv');

MySQL может использовать индекс на company для этого запроса просто отлично. Нет необходимости делать какой-либо СОЮЗ.

Более сложный случай заключается в том, что у вас есть условие OR, которое включает в себя два разных столбца.

select username from users where company = 'bbc' or city = 'London';

Предположим, что на company есть индекс и отдельный индекс на city. Учитывая, что MySQL обычно использует только один индекс для таблицы в заданном запросе, какой индекс следует использовать? Если он использует индекс на company, все равно придется выполнять сканирование таблицы, чтобы найти строки, где city - Лондон. Если он использует индекс в city, ему нужно будет выполнить сканирование таблицы для строк, где company - bbc.

Решение UNION для этого типа случая.

select username from users where company = 'bbc' 
union
select username from users where city = 'London';

Теперь каждый подзапрос может использовать индекс для своего поиска, а результаты подзапроса объединяются с помощью UNION.


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

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

Разница зависит от данных в таблице и от условий поиска. Единственный способ определить наилучшее решение для данного запроса - попробовать оба метода в профилировщике запросов MySQL и сравнить их производительность.

Ответ 2

Это не тот же запрос.

У меня нет большого опыта работы с MySQL, поэтому я не уверен, что оптимизатор запросов делает или не делает, но вот мои мысли из моего общего фона (в основном, ms sql server).

Как правило, анализатор запросов может принимать вышеуказанные два запроса и выводить из них один и тот же план (если они были одинаковыми), поэтому это не имеет значения. Я бы заподозрил, что между этими запросами нет разницы в производительности (что эквивалентно)

select distinct username from users where company = ‘bbc’ or company = ‘itv’;

и

select username from users where company = ‘bbc’ 
union
select username from users where company = ‘itv’;

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

select username from users where company = ‘bbc’ or company = ‘itv’;

и

select username from users where company = ‘bbc’ 
union all
select username from users where company = ‘itv’;

Ответ 3

Это зависит от того, что делает оптимизатор в зависимости от размера данных, индексов, версии программного обеспечения и т.д.

Я бы предположил, что использование OR даст оптимизатору лучший шанс найти некоторую эффективность, поскольку все находится в одном логическом выражении.

Кроме того, UNION имеет некоторые накладные расходы, поскольку он создает набор reset (без дубликатов). Каждое утверждение в UNION должно выполняться довольно быстро, если компания индексируется... не уверен, что это действительно будет делать двойную работу.

Нижняя строка

Если у вас действительно есть жгучая потребность сжать каждый бит скорости из вашего запроса, вероятно, лучше просто пойти с формой, которая наилучшим образом свяжет ваше намерение... OR

Update

Я также хотел упомянуть IN. Я считаю, что следующий запрос даст лучшую производительность, чем OR (это также форма, которую я предпочитаю):

select username from users where company in ('bbc', 'itv');

Ответ 4

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

Версия or на практике намного лучше, поскольку она будет сканировать только один раз. Он также будет использовать индекс только один раз, если он доступен.

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

Ответ 5

Ответ Билла Карвина довольно прав. Когда обе части оператора OR имеют свой собственный индекс, лучше выполнять объединение, потому что, как только у вас есть небольшое подмножество результатов, проще отсортировать их и устранить дубликаты. Общая стоимость почти меньше, чем использование только одного индекса (для одного столбца) и сканирования таблицы для другого столбца (поскольку mysql использует только один индекс для одного столбца).

Это зависит от структуры таблицы и потребностей вообще, но в больших таблицах объединение дало мне лучшие результаты.