Описание оптимизации выражений WHERE помещено в раздел, посвященный
SELECT, потому что они главным образом используются в запросах SELECT, но
для выражений WHERE в операторах DELETE и UPDATE используются те же
способы оптимизации.
Отметим также, что данный раздел неполон. В MySQL реализовано много возможностей оптимизации, и у нас не было времени, чтобы задокументировать их все.
Ниже перечислены некоторые из оптимизации, выполняемых MySQL:
-
Удаляются ненужные скобки:
((a AND b) AND c OR (((a AND b) AND (c AND d)))) -> (a AND b AND c) OR (a AND b AND c AND d)
-
Константы заменяются значениями:
(a<b AND b=c) AND a=5 -> b>5 AND b=c AND a=5
-
Удаляются условия для констант (требуется при замене констант значением):
(B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6) -> B=5 OR B=6
Константные выражения, используемые индексами, оцениваются только один раз.
Для таблиц
HEAPиMyISAMфункцияCOUNT(*), которая вызывается для одной таблицы и не содержит предложенияWHERE, берется непосредственно из табличной информации. Это делается также для любого выраженияNOTNULL, в котором используется только одна таблица.Недопустимые константные выражения выявляются на ранних этапах. MySQL быстро обнаруживает, что некоторые операторы
SELECTнеосуществимы и не возвращают строк.Выполняется слияние выражения
HAVINGсWHERE, если не используется предложениеGROUP BYили групповые функции (COUNT(), MIN()...).Для каждого подчиненного связывания создается более простое предложение
WHERE, чтобы ускорить оценкуWHEREдля каждого подчиненного связывания а также чтобы пропустить записи как можно быстрее.-
Все константные таблицы считываются в первую очередь, перед любыми другими таблицами в запросе. К константным таблицам относятся следующие:
Пустая таблица или таблица с 1 строкой.
Таблица, которая используется с выражением
WHEREдля индексаUNIQUE, илиPRIMARY KEY, где все части индекса используются с константными выражениями и части индекса определены какNOT NULL.
Все эти таблицы используются как константные таблицы:
mysql> SELECT * FROM t WHERE primary_key=1; mysql> SELECT * FROM t1,t2 -> WHERE t1.primary_key=1 AND t2.primary_key=t1.id; Лучшая комбинацию связывания для связывания таблиц находится путем испытания всех возможных вариантов. Если все столбцы в предложениях
ORDER BYиGROUP BYпринадлежат одной таблице, эта таблица рассматривается первой при связывании.Если имеется выражение
ORDER BYи отличное от него выражениеGROUP BY, или если выраженияORDER BYилиGROUP BYсодержат столбцы не только из первой таблицы в очереди на связывание, но и из других таблиц, то тогда создается временная таблица.Если используется
SQL_SMALL_RESULT, MySQL будет применять временную таблицу, которую разместит в памяти.Запрашивается каждый индекс таблицы, и используется лучший, охватывающий менее 30% строк. Если такой индекс найти нельзя, используется быстрое сканирование таблицы.
В некоторых случаях MySQL может читать данные из индекса даже без обращения к файлу данных. Если все столбцы, используемые в индексе, числовые, то для выполнения запроса будет использоваться только индексное дерево.
Перед выводом каждой записи пропускаются те, которые не соответствуют выражению
HAVING.
Вот некоторые примеры очень быстрых запросов:
mysql> SELECT COUNT(*) FROM tbl_name;
mysql> SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
mysql> SELECT MAX(key_part2) FROM tbl_name
-> WHERE key_part_1=constant;
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1,key_part2,... LIMIT 10;
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;
Для выполнения следующих запросов используется только индексное дерево (предполагается, что индексированные столбцы числовые):
mysql> SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;
mysql> SELECT COUNT(*) FROM tbl_name
-> WHERE key_part1=val1 AND key_part2=val2;
mysql> SELECT key_part2 FROM tbl_name GROUP BY key_part1;
Следующие запросы используют индексацию, чтобы получить отсортированные строки без дополнительного прохода для сортировки:
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1,key_part2,... ;
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1 DESC,key_part2 DESC,... ;