Знакомая история: повесил индекс, а запрос как тормозил, так и тормозит.
Индекс вроде есть, но планировщик смотрит на него и проходит мимо.
Собрал самые частые причины, из-за которых так происходит.
1. Обернул колонку в функцию 🔧 Вот это ломает индекс чаще всего:
WHERE YEAR(created_at) = 2024
Как только колонка попадает внутрь функции, индекс по ней уже не применить — и привет, seq scan по всей таблице. Лечится диапазоном:
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01'
Ну или заводишь функциональный индекс, если без функции совсем никак.
2. LIKE, который начинается с
% 🔍 Тут всё просто:WHERE name LIKE '%anton' -- бесполезно
WHERE name LIKE 'anton%' -- работает
B-tree умеет искать по началу строки, а не по середине. Если тебе реально нужен поиск по куску внутри — это уже полнотекстовый индекс или триграммы (в постгресе pg_trgm).
3. Порядок колонок в составном индексе 📚 Индекс
(a, b) устроен как телефонная книга: сначала сортировка по a, и только внутри неё по b. Поэтому запрос, где есть только b, его не подхватит:INDEX (user_id, created_at)
WHERE user_id = 5 -- норм
WHERE user_id = 5 AND created_at… -- норм
WHERE created_at > … -- мимо, левого префикса нет
4. Типы не совпали 🎭 Классика, на которой все хоть раз спотыкались:
-- phone у нас VARCHAR
WHERE phone = 89991234567 -- число против строки, индекс мимо
WHERE phone = '89991234567' -- порядок
База молча приведёт типы сама, а заодно тихо выкинет индекс.
Так что следи, чтобы тип значения совпадал с колонкой.
5. Индекс на колонке, где всего два значения 🎲
is_active, gender и прочие флаги индексировать почти бессмысленно. Если под условие подходит половина таблицы, планировщику дешевле прочитать её целиком, чем скакать туда-сюда по индексу.
И он тут прав.
Индексы хороши там, где значение отсекает много строк, а не половину.
6.
SELECT * мешает covering index 📦 Иногда индекс уже содержит все поля, которые тебе нужны, и база может отдать ответ прямо из него, не заглядывая в таблицу. Красота. Но стоит написать
SELECT * — и она вынуждена лезть в таблицу за каждой строкой ради остальных колонок. Бери только то, что реально используешь.В общем, индекс — это не «создал и забыл».
Прежде чем гадать на кофейной гуще, открой
EXPLAIN ANALYZE и посмотри, что там планировщик на самом деле делает. Он-то не соврёт.
А у вас какой случай в духе «индекс есть, но его как бы нет» бесил сильнее всего? 🤔
#sql #database #postgres #backend #performance #dev