Случай A
Запрос:
WHERE thread_id = 12345
AND placeholder = FALSE
ORDER BY some_column DESC
LIMIT 20
Индекс:
(thread_id, date_created)
План:
Index is used
Using Where
Using filesort
Нет проблем там, верно? Если используется индекс (для частичного соответствия WHERE
условию), нам все еще нужна операция сортировки, чтобы упорядочить результаты по some_column
(которого нет в индексе). Нам также нужна дополнительная проверка (Using Where), чтобы сохранить только те строки, которые соответствуют 2-му условию. ХОРОШО.
Случай B (вопрос)
Запрос:
WHERE thread_id = 12345
AND placeholder = FALSE
ORDER BY date_created DESC
LIMIT 20
Индекс:
(thread_id, date_created)
План:
Index is used
Using Where
-- no "Using filesort"
Так почему же здесь не нужна сортировка ? Потому что индекса достаточно для сортировки по запросу. Конечно, существует дополнительная проблема дополнительного условия ( AND placeholder = FALSE
), которое не включено в индекс.
Хорошо, но нам здесь не нужна сортировка. Индекс может предоставить нам результаты, которые соответствуют первому условию ( WHERE thread_id = 12345
) и находятся в требуемом порядке для вывода. Единственная дополнительная проверка, которая нам нужна - и то, что делает план - это получить строки из таблицы в порядке, указанном в индексе, и проверять это 2-е условие, пока мы не получим 20 совпадений. Вот что означает ** Используя Где "".
Мы можем получить 20 совпадений в первых 20 строках (что действительно хорошо и быстро) или в первых 100 (все еще, вероятно, достаточно быстро) или в первых 1000000 (вероятно, очень, очень медленно), или мы можем получить только 19 совпадений из таблица даже после чтения всех соответствующих строк из индекса (действительно очень медленно на большой таблице). Все зависит от распределения данных.
Случай C (даже лучший план)
Запрос:
WHERE thread_id = 12345
AND placeholder = FALSE
ORDER BY date_created DESC
LIMIT 20
Индекс:
(placeholder, thread_id, date_created)
План:
Index is used
-- no "Using Where"
-- no "Using filesort"
Теперь наш индекс соответствует как условиям, так и порядку. План довольно прост: получить первый * 20 матчей из индекса и прочитать соответствующие строки из таблицы. Никакой дополнительной проверки (без «Использования где») и никакой сортировки (без «Использование сортировки файлов») не требуется.
first *: первые 20 при чтении индекса назад от конца (как у нас ORDER BY .. DESC
), но это не проблема. Индексы B-дерева можно читать вперед и назад с почти одинаковой производительностью.