В MySQL влияет ли порядок столбцов в предложении WHERE на производительность запроса?

38

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

Запрос в вопросе, у меня есть три ANDс в предложении WHERE

Имеет ли значение порядок пунктов?

Например, если я сначала поставлю предложение ASI_EVENT_TIME (поскольку это приведет к удалению большинства результатов из любого из предложений.

Это улучшит время выполнения запроса?

QUERY:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

ОБЪЯСНЕНИЕ запроса:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

С помощью:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5

Патрик
источник
Возможно, ORDER BY занимает столько времени. «Использование сортировки файлов» может быть очень медленным. Я обнаружил, что упорядочивание в логике приложения намного быстрее, чем при использовании ORDER BY.
Маклема
Я задал этот же вопрос некоторое время назад (до этого сайта) на stackoverflow. Проверьте ссылки на ответы, которые я получил там. stackoverflow.com/questions/3805863/…
Скотт
2
@maclema - Если ваше приложение не работает на гораздо более быстрой машине, чем ваша база данных, ваше утверждение, безусловно, не соответствует действительности, не говоря уже о бессмысленном бремени всей этой логики сортировки в вашем приложении. order byпринадлежит в базе данных.
Джек Дуглас

Ответы:

24

Не думаю. Оптимизатор запросов должен быть достаточно умным.

Вы можете попробовать переставить предложения WHERE и увидеть, что EXPLAINS говорит вам то же самое в каждом случае.


О том, что можно сделать для оптимизации этого запроса: есть ли индекс для ASI_EVENT_TIME? (для этого запроса я считаю наиболее важным, поскольку вы также сортируете результаты по нему).

Есть ли индексы в двух других полях (ASI_SEISMO_ID и ASI_ACTIVITY_ID)?

Было бы полезно, если бы вы опубликовали структуру таблицы.

ypercubeᵀᴹ
источник
Я никогда не думал создать индекс времени событий. Я попробую это завтра на dev db и посмотрю, есть ли заметная разница.
Патрик
@Patrick Предполагая, что все другие запросы, которые будут использовать этот индекс, упорядочивают эту дату в порядке убывания, вы также должны упорядочить ключ индекса (activity_seismo_info.ASI_EVENT_TIME) в порядке убывания.
Мэтт М
@ MattM Я не знал, что вы могли бы заказать индексный ключ. Круто Если я сделаю заказ индексного ключа, это обязательно повредит упорядочению производительности в направлении, противоположном тому, что оно хуже, чем отсутствие индексного ключа?
Патрик
@ Патрик Вы правы. Мой мозг застрял на земле SQL Server. Вы можете указать порядок сортировки в MYSQL, и он будет анализироваться, но он игнорируется. Все индексы отсортированы в порядке возрастания в MYSQL. Извините за путаницу.
Мэтт М
13

Из документации :

Если таблица имеет индекс из нескольких столбцов, любой крайний левый префикс индекса может использоваться оптимизатором для поиска строк. Например, если у вас есть индекс из трех столбцов (col1, col2, col3), у вас есть индексированные возможности поиска для (col1), (col1, col2) и (col1, col2, col3).

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

Так что да, он должен быть таким же, как порядок столбцов в составном индексе .

Gaius
источник
4
Если таблица имеет индекс из нескольких столбцов, выбор столбцов слева имеет значение, но порядок, в котором вы выбираете, не имеет значения. Так что, если у вас есть индекс a, b, c, и у вас есть, WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'и индекс по-прежнему подходит для использования.
текселат
10

Нет, это не важно.

Оптимизатор выполняет кучу простых преобразований сразу после анализа SQL - это одно из них.

Морган Токер
источник
8

ГДЕ ФУ И БАР

оптимизирует так же, как

ГДЕ БАР И ФУ

Тем не мение,

ГДЕ НЕ РАВНО # 1 И НЕ РАВНО # 2

Не удается оптимизировать обе части. Например,

ГДЕ МЕЖДУ 1, 3 И Б> 17

не может эффективно использовать INDEX (a, b) или INDEX (b, a)

Чтобы выразить это по-другому, сначала используются любые '=' тесты AND'd вместе в предложении WHERE, затем один может быть обработан не - '=' (IN, BETWEEN,> и т. Д.). Не более одного можно эффективно оптимизировать.

Ваш запрос имеет 3 таких пункта.

Как оказалось, INDEX (EVENT_TIME), вероятно, наиболее полезен - он поможет с одним из AND, и его можно использовать, чтобы избежать «файловой сортировки» для ORDER BY.

Если нет повторяющихся строк (почему, черт возьми, будет?), Тогда избавьтесь от DISTINCT. Это вызывает еще больше усилий.

Пожалуйста, предоставьте SHOW CREATE TABLE и SHOW TABLE STATUS, задавая вопросы о производительности.

Обновление ... Более новые версии (например, MySQL 5.7) могут в некоторых ситуациях работать IN( list of constants )почти так же, как =. Чтобы не рисковать, придерживайтесь этого порядка (каждая часть необязательна):

  1. Любое количество =.
  2. Некоторые INs.
  3. Максимум один диапазон.
Рик Джеймс
источник
1

MySQL, где документация по оптимизации гласит:

Возможно, вы захотите переписать свои запросы, чтобы ускорить выполнение арифметических операций, жертвуя при этом удобочитаемостью. Поскольку MySQL выполняет аналогичные оптимизации автоматически , вы часто можете избежать этой работы и оставить запрос в более понятной и понятной форме. Ниже приведены некоторые из оптимизаций, выполненных MySQL:

  • ...

  • Для каждой таблицы в объединении, более простой WHERE построен , чтобы получить быструю оценку WHERE для таблицы , а также для пропуска строк как можно скорее .

  • Каждый индекс таблицы запрашивается, и лучший индекс используется, если только оптимизатор не считает, что более эффективно использовать сканирование таблицы . Одно время использовалось сканирование, основанное на том, охватывал ли лучший индекс более 30% таблицы, но фиксированный процент больше не определяет выбор между использованием индекса или сканированием. Оптимизатор теперь стал более сложным и основывает свою оценку на дополнительных факторах, таких как размер таблицы, количество строк и размер блока ввода-вывода.

Таким образом, для оптимизатора запросов целесообразно опустить порядок HOW, в котором мы использовали столбцы в запросе (не только MySQL, но и SQL - декларативный язык, и он должен делать то, что мы хотим, а не то, что мы хотим).

Однако я все еще люблю иметь такой же вид для столбцов составного ключа в запросе, но иногда это неизбежно, например, когда мы используем ORM или ActiveRecord, в некоторых средах, таких как yii2, настройка критериев отношения будет добавлена ​​в конце в состоянии «включено», но нам все еще нужны возможности QueryBuilders в разных частях приложения.

Alix
источник
-2

Любое поле, которое используется в ваших предложениях WHERE / HAVING и имеет высокую селективность (количество уникальных значений / общее количество записей> 10% ~ 20%), ДОЛЖНО быть проиндексировано.

Итак, если в вашем ASI_EVENT_TIMEстолбце много возможных значений, сначала внесите их в указатель. Затем, как сказал @ypercube, попробуйте переставить их и посмотрите, что EXPLAIN говорит вам. Должно быть все вокруг одинаково.

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

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

глаз
источник
8
-1 Индексирование каждого столбца НЕ является лучшей практикой. Каждый индекс стоит вам несколькими способами. Убедитесь, что вы выбрали хорошие индексы, которые обычно состоят из нескольких столбцов, обычно в порядке избирательности и используемой частоты. Это может быть косой SQL Server, но информация индекса все еще действительна: sqlskills.com/BLOGS/KIMBERLY/post/… .
Эрик Хамфри - LotsAhelp
@Eric Humphrey +1 За объяснение и ссылку на сайт Кимберли.
Мэтт М
Вы ошибаетесь, иногда индекс по столбцу снижает производительность при выполнении запросов на выборку: mysqlperformanceblog.com/2007/08/28/… . Вы никогда не должны использовать правило: иногда это работает, иногда нет.
Sumar
Хорошо, я согласен. Тем не менее, это справедливо в случае низкой избирательности значения. Учитывая тип данных, который использует Патрик (автор этого вопроса), а именно DATETIME, рекомендуется индексирование. Обычно этот тип поля имеет довольно большой набор значений, если только не возникает странная ситуация, когда он использует только несколько возможных дат. * Я отредактирую свой ответ выше, чтобы сделать более ясное и правильное утверждение.
Глаз