Оптимизация MySQL: замените OR с помощью UNION [duplicate]

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

Пока int(input()) достаточно для одного целого числа, я не нашел прямого способа ввода двух целых чисел. Я пробовал это:

num = input()
num1 = 0
num2 = 0

for i in range(len(num)):
    if num[i] == ' ':
        break

num1 = int(num[:i])
num2 = int(num[i+1:])

Теперь я использую num1 и num2 как целые числа. Надеюсь, это поможет.

43
задан hjpotter92 7 July 2014 в 18:34
поделиться

5 ответов

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

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

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

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

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

Более сложным является случай, когда у вас есть условие 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 и сравнить их производительность.

71
ответ дан Bill Karwin 22 August 2018 в 12:13
поделиться
  • 1
    Цитата, которую я предоставил, была точным примером в этой статье. Таким образом, не было ничего неправильного толкования. Я знал, что использование UNION vs. OR было категорически неверным . Но я считаю это правильным, так как он рассматривал исходный пример как неправильный , предоставляя пример использования того, что, по мнению автора, означал . – Jason McCreary 13 December 2012 в 21:16
  • 2
    Увы, автор, возможно, писал о решении, не понимая случаев, когда решение полезно и не нужно. Или он, возможно, основывал свои знания на древней версии MySQL, которая не оптимизировала предикаты IN(). – Bill Karwin 13 December 2012 в 21:19
  • 3
    @BillKarwin, если индексируются два разных столбца, тогда MySQL не будет выполнять «Оптимизацию слияния индексов». получить объединенный результат отдельных сканирований на основе обоих двух индексов? – sactiw 16 November 2015 в 14:51
  • 4
    @sactiw, Иногда. На практике я обнаружил, что оптимизатор не использует слияние индексов, когда этого можно было бы ожидать, поэтому я не полагаюсь на это. – Bill Karwin 16 November 2015 в 15:10
  • 5
    Я, наконец, понимаю необходимость СОЮЗА. Благодаря! Я заказываю твою книгу из Амазонки. – isapir 3 February 2016 в 04:56

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

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

-1
ответ дан Çağatay Gürtürk 22 August 2018 в 12:13
поделиться

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

У меня нет большого опыта работы с MySQL, поэтому я не уверен, что оптимизатор запросов делает или не делает, но вот мои мысли от моего общего background (в основном 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’;
5
ответ дан Darren Kopp 22 August 2018 в 12:13
поделиться
  • 1
    + о запросах не совпадают. Тем не менее, UNION ALL все еще дает тот же EXPLAIN, что и UNION. – Jason McCreary 6 December 2012 в 21:13

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

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

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

Bottom line

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

Обновление

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

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

2
ответ дан David J 22 August 2018 в 12:13
поделиться

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

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

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

0
ответ дан Gordon Linoff 22 August 2018 в 12:13
поделиться
  • 1
    Чтобы быть понятным, UNION также будет использовать индекс, если он доступен. Но он будет сканировать обе таблицы . Просто меньший набор данных, затем объедините их обратно вместе. – Jason McCreary 6 December 2012 в 23:52
Другие вопросы по тегам:

Похожие вопросы: