ОБЪЕДИНЕНИЕ производительности SQL против ИЛИ

#mysql #query-optimization

#mysql #sql #Производительность #союз

Вопрос:

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

При использовании SQL замените операторы 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 :

введите описание изображения здесь

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

введите описание изображения здесь

Разве это не означает UNION , что это удваивает работу?

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

Вопрос

Я ошибаюсь?

Комментарии:

1. Я бы подумал, что UNION это делает больше работы, поскольку необходимо удалить дубликаты, где фильтр будет извлекать указанные критерии. Я удивлен, что он не рекомендует использовать IN .

2. Это может быть правдой, если mysql не может использовать индексы, когда есть OR WHERE предложение in .

3. @Игорь Романченко, поддержите это ответом.

4. Я бы предположил, что анализатор запросов перепишет операторы or в оператор IN, поскольку они эквивалентны

5. @Даррен Копп, я почти уверен, что все наоборот. По крайней мере, в MySQL в любом случае.

Ответ №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 обычно использует только один индекс для каждой таблицы в данном запросе, какой индекс он должен использовать? Если он использует индекс on company , ему все равно придется выполнять сканирование таблицы, чтобы найти строки, где city находится Лондон. Если он использует индекс on city , ему нужно будет выполнить сканирование таблицы на наличие строк, где company находится bbc.

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

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

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


Анонимный пользователь предложил отредактировать мой ответ выше, но модератор отклонил редактирование. Это должен был быть комментарий, а не редактирование. Претензия предлагаемого редактирования заключалась в том, что ОБЪЕДИНЕНИЕ должно сортировать результирующий набор для устранения повторяющихся строк. Это замедляет выполнение запроса, и поэтому оптимизация индекса является промывкой.

Мой ответ заключается в том, что индексы помогают сократить результирующий набор до небольшого количества строк, прежде чем произойдет ОБЪЕДИНЕНИЕ. ОБЪЕДИНЕНИЕ действительно устраняет дубликаты, но для этого ему нужно только отсортировать небольшой набор результатов. Могут быть случаи, когда предложения WHERE соответствуют значительной части таблицы, и сортировка во время ОБЪЕДИНЕНИЯ так же дорога, как простое сканирование таблицы. Но чаще всего результирующий набор уменьшается за счет индексированных поисковых запросов, поэтому сортировка намного дешевле, чем сканирование таблицы.

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

Комментарии:

1. Приведенная мной цитата была точным примером в статье. Так что не было ничего для неправильного толкования. Я знал, что использование UNION vs OR . не было категорически верным . Но я отмечаю это как правильное, поскольку оно рассматривало исходный пример как неправильный , в то же время предоставляя пример использования того, что, вероятно, имел в виду автор.

2. Увы, автор, возможно, писал о решении, не понимая случаев, когда решение полезно или не нужно. Или он, возможно, основывал свои знания на древней версии MySQL, которая также не оптимизировала IN() предикаты.

3. @BillKarwin если проиндексированы два разных столбца, не будет ли MySQL выполнять «Оптимизацию слияния индексов», чтобы получить объединенный результат отдельных сканирований на основе обоих двух индексов?

4. Я, наконец, понимаю необходимость ОБЪЕДИНЕНИЯ. Спасибо! Я заказываю вашу книгу с Amazon.

5. Это многое объясняет, особенно время запроса, когда в предложении Where выполняется проверка столбцов из одного объединения или другого столбца из другого объединения. Спасибо!

Ответ №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’;
 

Комментарии:

1. о том, что запросы не совпадают. Тем не менее, UNION ALL по-прежнему дает то EXPLAIN же UNION самое, что и .

2. UNION ALL обычно быстрее, чем UNION . Последнее подразумевает UNION DISTINCT , тем самым требуя детального перехода по временной таблице. Более новые версии избегают таблицы temp в определенных ситуациях, тем самым помогая больше. Приведенный or вами пример всегда быстрее, потому что он может использовать INDEX(company)

Ответ №3:

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

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

Кроме того, ОБЪЕДИНЕНИЕ имеет некоторые накладные расходы, поскольку оно создает набор сброса (без дубликатов). Каждый оператор в ОБЪЕДИНЕНИИ должен выполняться довольно быстро, если company индексируется… не уверен, что это действительно удвоит работу.

Итог

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

Обновить

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

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

Ответ №4:

Это мой результат теста


При использовании UNION — Query потребовалось 13.8699
несколько секунд, чтобы проверить основной тип выбора — 247685

когда использование ИЛИ — запроса заняло 0.0126 несколько секунд, и строка проверила первичный тип выбора — 495371

MySQL использует один индекс для запроса, поэтому, когда мы используем or mysql, мы используем индекс одного столбца и сканируем всю таблицу для другого столбца

другая часть объединения может работать 2 раза

вот почему or быстрее, чем union

Комментарии:

1. Это помогло бы, если бы вы показали свой код. А также сколько раз вы повторяли эксперимент.

Ответ №5:

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

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

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

Комментарии:

1. Просто для ясности, UNION также будет использоваться индекс, если он доступен. Но он будет сканировать обе таблицы . Просто уменьшите набор данных, а затем объедините их обратно вместе.

2. нет-нет-нет, если вы используете or / in , вы собираетесь использовать «сканирование диапазона индексов», а в случае union / union all вы собираетесь использовать non-unique или даже primary key lookup плюс index merge

3. @Evgeniyafanasyev . , , Результаты explain совершенно ясно показывают, что в таблице нет индексов.

4. Спасибо за ваш комментарий. В вопросе не указано условие «нет индексов в таблице», как и в вашем ответе. Если бы вы поместили это в начале своего ответа, это помогло бы таким людям, как я, искать свои сценарии.

5. IN и OR одинаковы. Вы можете убедиться в этом, EXPLAIN убедившись, что оптимизатор превращает одно в другое.

Ответ №6:

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

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

Комментарии:

1. вы сказали mysql only uses one index for one column — это неправда. У вас может быть свой столбец во многих индексах.

2. Во время выполнения запроса mysql использует только один индекс для одного столбца. Речь идет не о возможности определения нескольких индексов в одном столбце.

3. Это снова неверно. MySQL использует один индекс для запроса, а не для одного столбца.

4. Давайте сформулируем это еще точнее: «один индекс на SELECT «. (Это позволяет избежать двусмысленности того, является ли a UNION одним или несколькими «запросами».)

5. @RickJames Я говорю «один индекс на ссылку на таблицу», потому что в запросе с объединениями каждая ссылка на таблицу может использовать индекс. Даже при выполнении самосоединений каждая табличная ссылка на одну и ту же таблицу может использовать другой индекс.