Ответ
Даже при наличии индекса запрос может выполняться медленно. Вот почему:
-
Низкая селективность индекса. Индекс неэффективен, если он построен по полю с малым количеством уникальных значений (например,
пол,статус_заказас 2-3 вариантами). В этом случае СУБД может решить, что полное сканирование таблицы будет быстрее, чем работа с индексом. -
Использование функций над индексированным столбцом. Применение функций к столбцу в условии
WHEREделает использование индекса невозможным.-- ПЛОХО: Индекс по `created_at` не будет использован SELECT * FROM orders WHERE YEAR(created_at) = 2023; -- ХОРОШО: Индекс будет использован SELECT * FROM orders WHERE created_at >= '2023-01-01' AND created_at < '2024-01-01'; -
Индекс не покрывает запрос (Not a Covering Index). Если индекс включает только поля из
WHERE, но не все поля изSELECT, СУБД сначала находит нужные записи по индексу, а затем для каждой из них обращается к таблице за остальными данными. Это может быть медленно, если таких записей много. -
Неявное преобразование типов. Если тип данных в условии запроса не совпадает с типом столбца в таблице, СУБД может быть вынуждена преобразовывать типы, что мешает использованию индекса.
-- user_id имеет тип INT, а в запросе передается строка. Индекс может не использоваться. WHERE user_id = '123' -
Фрагментация индекса. В таблицах с частыми операциями
INSERT,UPDATE,DELETEиндекс может стать фрагментированным, что снижает скорость поиска по нему. Требуется его реорганизация (REORGANIZE) или перестроение (REBUILD). -
Поиск по шаблону с
LIKEв начале строки. Индекс не будет использоваться, если шаблон поиска начинается с%.-- ПЛОХО: Индекс по `name` не используется (Full Scan) WHERE name LIKE '%John%' -- ХОРОШО: Индекс используется (Index Range Scan) WHERE name LIKE 'John%'
Ответ 18+ 🔞
А, слушай, вот тебе классика жанра! Сидит такой админ, весь из себя довольный, понаставил индексов, как ёлки в лесу, и думает: "Ну теперь-то у меня всё летает, пиздец!" А потом бац — запрос тормозит, как чугунный мост. И он такой: "Какого хуя?! У меня же индекс есть!". А причина-то, блядь, может быть в какой-нибудь хитрожопой мелочи.
Вот, смотри, на какие грабли обычно наступают:
-
Индекс по полю, где значений — три штуки. Ну, типа
пол('М', 'Ж', 'Не скажу') илистатус('новый', 'в работе', 'ёбнут'). Это называется низкая селективность. База посмотрит на такой индекс, плюнет и скажет: "Да похуй, проще всю таблицу прочитать, чем по этому говнищу скакать". И сделает Full Scan. Вот и вся магия. -
Запросы с функциями, блядь. Самый частый пиздец. Индекс — это как алфавитный указатель в книге. А ты в запросе этот указатель пытаешься читать через зеркало.
-- Вот это говно. Индекс по `created_at` лежит и плачет. SELECT * FROM orders WHERE YEAR(created_at) = 2023; -- А вот так — уже человек. Индекс отработает как надо. SELECT * FROM orders WHERE created_at >= '2023-01-01' AND created_at < '2024-01-01'; -
Индекс не покрывающий (Not a Covering Index). Представь: индекс — это оглавление с номерами страниц. Ты по нему быстро нашёл, что нужная тебе хуйня на страницах 10, 23 и 45. Но чтобы её прочитать, тебе всё равно надо листать всю книгу туда-сюда. Вот так и база: нашла ID записей по индексу, а потом ещё и в саму таблицу лезет за каждую, чтобы взять остальные поля из
SELECT. Если записей много — пиздец и задержка. -
Неявное преобразование типов. О, это тонкий момент, ёпта! Допустим,
user_idу тебя в таблице — число (INT). А в запросе ты ему суёшь строку.WHERE user_id = '123' -- База морщится: "Бля, надо '123' в число превратить... Ладно, проще индекс проигнорить".И всё, приехали. Индекс в ауте.
-
Фрагментация. Таблицу часто обновляют, удаляют, вставляют — индекс внутри превращается в швейцарский сыр, дырок больше, чем структуры. Искать по такому — одно мучение. Его надо иногда перестраивать (
REBUILD), как старый забор. -
LIKE с процентом в начале. Ну это анекдот уже. Индекс по строковому полу — это отсортированный список. А ты ищешь
'%John%'. Это как в телефонной книге, отсортированной по фамилиям, пытаться найти всех, у кого внутри имени есть буквы "ohn". Придётся читать всю книгу, блядь. Индекс тут не помощник.WHERE name LIKE '%John%' -- Пиздец и Full Scan. WHERE name LIKE 'John%' -- А вот так уже можно, молодца.
Вот так вот, казалось бы, индекс есть, а запрос ползёт, как улитка по шершавой поверхности. Волнение ебать! Надо всегда смотреть в план выполнения, там все эти фокусы видны как на ладони.