10.2.1.19 Оптимизация запросов LIMIT
Если вам нужно только определенное количество строк из набора результатов, используйте в запросе условие LIMIT, а не извлекайте весь набор результатов и отбрасывайте лишние данные.
MySQL иногда оптимизирует запрос, содержащий условие LIMIT
и не содержащий условие row_countHAVING:
Если вы выбираете только несколько строк с помощью
LIMIT, MySQL в некоторых случаях использует индексы, в то время как обычно предпочитал бы выполнить полное сканирование таблицы.-
Если вы объединяете
LIMITсrow_countORDER BY, MySQL прекращает сортировку, как только найдет первыеrow_countстрок отсортированного результата, а не сортирует весь результат. Если сортировка выполняется с использованием индекса, это очень быстро. Если необходимо выполнить filesort, все строки, которые соответствуют запросу без условияLIMIT, выбираются, и большинство или все из них сортируются, прежде чем будут найдены первыеrow_countстрок. После нахождения начальных строк MySQL не сортирует оставшуюся часть набора результатов.Одним проявлением этого поведения является то, что запрос
ORDER BYс условиемLIMITи без него может возвращать строки в разном порядке, как описано далее в этом разделе. Если вы объединяете
LIMITсrow_countDISTINCT, MySQL прекращает выполнение, как только найдетrow_countуникальных строк.В некоторых случаях запрос
GROUP BYможет быть обработан путем чтения индекса в порядке (или сортировки по индексу), а затем вычисления сводок до тех пор, пока значение индекса не изменится. В этом случаеLIMITне вычисляет ненужныеrow_countGROUP BYзначения.-
Как только MySQL отправит нужное количество строк клиенту, он прерывает запрос, если вы не используете
SQL_CALC_FOUND_ROWS. В этом случае количество строк можно получить с помощьюSELECT FOUND_ROWS(). См. Раздел 14.15, «Функции информации». LIMIT 0быстро возвращает пустой набор. Это может быть полезно для проверки корректности запроса. Также это может быть использовано для получения типов столбцов результатов в приложениях, использующих API MySQL, который предоставляет метаданные набора результатов. С помощью программы командной строки mysql вы можете использовать опцию--column-type-infoдля отображения типов столбцов результатов.Если сервер использует временные таблицы для обработки запроса, он использует условие
LIMITдля расчета необходимого объема места.row_countЕсли индекс не используется для
ORDER BY, но также присутствует условиеLIMIT, оптимизатор может избежать использования объединённого файла и отсортировать строки в памяти с помощью операцииfilesortв памяти.
Если несколько строк имеют идентичные значения в столбцах ORDER
BY, сервер свободен возвращать эти строки в любом порядке и может делать это по-разному в зависимости от общего плана выполнения. Другими словами, порядок сортировки этих строк не детерминирован относительно неотсортированных столбцов.
Один из факторов, влияющих на план выполнения, — LIMIT, поэтому запрос ORDER BY с условием LIMIT и без него может возвращать строки в разном порядке. Рассмотрим этот запрос, который отсортирован по столбцу category, но не детерминирован относительно столбцов id и rating:
mysql> SELECT * FROM ratings ORDER BY category;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 3 | 2 | 3.7 |
| 4 | 2 | 3.5 |
| 6 | 2 | 3.5 |
| 2 | 3 | 5.0 |
| 7 | 3 | 2.7 |
+----+----------+--------+
Включение LIMIT может повлиять на порядок строк внутри каждого значения category. Например, вот допустимый результат запроса:
mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 4 | 2 | 3.5 |
| 3 | 2 | 3.7 |
| 6 | 2 | 3.5 |
+----+----------+--------+
В каждом случае строки сортируются по столбцу ORDER
BY, что и требуется стандартом SQL.
Если важно обеспечить одинаковый порядок строк с условием LIMIT и без него, включите дополнительные столбцы в условие ORDER BY, чтобы сделать порядок детерминированным. Например, если значения id уникальны, вы можете заставить строки для данного значения category появляться в порядке id, отсортировав следующим образом:
mysql> SELECT * FROM ratings ORDER BY category, id;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 3 | 2 | 3.7 |
| 4 | 2 | 3.5 |
| 6 | 2 | 3.5 |
| 2 | 3 | 5.0 |
| 7 | 3 | 2.7 |
+----+----------+--------+
mysql> SELECT * FROM ratings ORDER BY category, id LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 3 | 2 | 3.7 |
| 4 | 2 | 3.5 |
| 6 | 2 | 3.5 |
+----+----------+--------+
Для запроса с условием ORDER BY или GROUP BY и условием LIMIT, оптимизатор по умолчанию пытается выбрать упорядоченный индекс, если это ускорит выполнение запроса. В случаях, когда использование другой оптимизации может быть быстрее, можно отключить эту оптимизацию, установив флаг optimizer_switch переменной среды prefer_ordering_index на значение off.
Пример: Сначала создадим и заполним таблицу t, как показано здесь:
# Create and populate a table t:
mysql> CREATE TABLE t (
-> id1 BIGINT NOT NULL,
-> id2 BIGINT NOT NULL,
-> c1 VARCHAR(50) NOT NULL,
-> c2 VARCHAR(50) NOT NULL,
-> PRIMARY KEY (id1),
-> INDEX i (id2, c1)
-> );
# [Insert some rows into table t - not shown]
Проверим, что флаг prefer_ordering_index включен:
mysql> SELECT @@optimizer_switch LIKE '%prefer_ordering_index=on%';
+------------------------------------------------------+
| @@optimizer_switch LIKE '%prefer_ordering_index=on%' |
+------------------------------------------------------+
| 1 |
+------------------------------------------------------+
Поскольку в следующем запросе есть условие LIMIT, мы ожидаем, что он будет использовать упорядоченный индекс, если это возможно. В этом случае, как видно из вывода EXPLAIN, он использует первичный ключ таблицы.
mysql> EXPLAIN SELECT c2 FROM t
-> WHERE id2 > 3
-> ORDER BY id1 ASC LIMIT 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
partitions: NULL
type: index
possible_keys: i
key: PRIMARY
key_len: 8
ref: NULL
rows: 2
filtered: 70.00
Extra: Using where
Теперь отключим флаг prefer_ordering_index и снова выполним тот же запрос; на этот раз он использует индекс i (который включает столбец id2, используемый в условии WHERE), и filesort:
mysql> SET optimizer_switch = "prefer_ordering_index=off";
mysql> EXPLAIN SELECT c2 FROM t
-> WHERE id2 > 3
-> ORDER BY id1 ASC LIMIT 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
partitions: NULL
type: range
possible_keys: i
key: i
key_len: 8
ref: NULL
rows: 14
filtered: 100.00
Extra: Using index condition; Using filesort
См. также Раздел 10.9.2, «Переключаемые оптимизации».
© 2025 Oracle
Licensed under the GPLv2 License.