Почему - или когда - MySQL не использует индексы для условий ИЛИ, если это делает для условий И? - PullRequest
2 голосов
/ 04 мая 2020

У меня есть таблица the_table с атрибутами the_table.id, the_table.firstVal и the_table.secondVal (конечно, первичный ключ - the_table.id).

После определения индекса для первого не атрибут ключа, например:

CREATE INDEX idx_firstval  
ON the_table (firstVal);

Результат EXPLAIN для следующего дизъюнктивного (OR) запроса

SELECT * FROM the_table WHERE the_table.firstVal = 'A' OR the_table.secondVal = 'B';

равен

| id    | select_type | table     | type    | possible_keys | key   | key_len   | ref   | rows  | Extra
| 1     | SIMPLE      | the_table | ALL     | idx_firstval  | NULL  | NULL      | NULL  | 3436  | Using where

, который показывает, что индекс idx_firstval не используется. Теперь результат EXPLAIN для следующего конъюнктивного (AND) запроса

SELECT * FROM the_table WHERE the_table.firstVal = 'A' AND the_table.secondVal = 'B';

равен

| id    | select_type   | table     | type  | possible_keys | key           | key_len   | ref   | rows  | Extra 
| 1     | SIMPLE        | the_table | ref   | idx_firstval  | idx_firstval  | 767       | const | 124   | Using index condition; Using where

, который показывает используемый индекс, на этот раз.

Почему MySQL предпочитает не использовать индексы для дизъюнктивного запроса, а для конъюнктивного?

Я искал SO, и, как следует из ответа в этой теме , "использование OR в запросе часто приводит к тому, что Оптимизатор запросов прекращает использование поиска индекса и возвращает его сканы ". Однако это не отвечает , почему это происходит, просто это делает .

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

Ответы [ 2 ]

2 голосов
/ 04 мая 2020

Поскольку план выполнения MySQL использует только один индекс для таблицы.

Если MySQL использует сканирование диапазона на idx_firstval для удовлетворения предиката равенства в столбце firstVal, то остается MySQL необходимо проверить условие в столбце secondVal.


При использовании AND, MySQL нужно только проверять строки, возвращенные из сканирования диапазона индекса. Набор строк, которые необходимо проверить, ограничен условием.


С OR, MySQL необходимо проверить строки, которые не были возвращены при сканировании диапазона индекса, все остальные строки в таблице. Без индекса это означает полное сканирование таблицы. И если мы выполняем полное сканирование таблицы для проверки secondVal, тогда будет дешевле проверить оба условия сканирования (т. Е. План, включающий доступ по индексу, а также полное сканирование, будет дороже). .)

(Если доступен составной индекс, содержащий как firstVal, так и secondVal, то для запроса OR возможно, что оптимизатор посчитает, что дешевле проверить все строки в таблице, выполнив полное сканирование индекса, а затем поиск страниц данных.)


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

SELECT a.*
  FROM the_table a
 WHERE a.firstVal = 'A'

UNION ALL

SELECT b.*
  FROM the_table b
 WHERE b.secondVal = 'B'
   AND NOT ( b.firstVal <=> 'A' )

(добавьте ORDER BY, если мы ожидаем, что строки будут возвращены в определенном порядке)

1 голос
/ 04 мая 2020

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

CREATE INDEX idx ON the_table (firstVal, secondVal);

Что касается того, почему MySQL использует индекс во втором случае, одна возможность может быть, если большинство записей в the_table имеют firstVal значения, которые не A. В этом случае простое знание того, что равенство the_table.firstVal = 'A' является ложным, будет означать, что весь результат предложения WHERE будет известен (как ложный). Таким образом, ответ о том, почему используется индекс, может иметь отношение к количеству ваших точных данных. Но в любом случае рассмотрите возможность использования составного индекса для охвата всех баз.

...