Классическая сцена: индекс создан, запрос по индексированной колонке, а план всё равно показывает последовательное чтение. Первая мысль — «индекс сломался». Почти всегда дело в другом.
Таблица маленькая
На тысяче строк планировщик прав: прочитать всё подряд дешевле, чем прыгать по индексу и потом ходить в heap за строками. Проверяется тривиально — залить данных побольше и посмотреть план заново. На учебных таблицах в пару сотен строк индекс не покажет себя никогда.
Статистика устарела
После массовой заливки автовакуум мог ещё не дойти. Планировщик считает селективность по устаревшей картине:
ANALYZE orders;
Условие не sargable
Функция на колонке убивает обычный btree-индекс:
-- индекс не применится
WHERE date_trunc('day', created_at) = '2026-08-28'
-- применится
WHERE created_at >= '2026-08-28' AND created_at < '2026-08-29'
Либо, если первая форма нужна по существу, — индекс по выражению.
Несовпадение типов
Колонка bigint, а в запросе строковый литерал. Приведение типа
происходит на стороне колонки, и индекс снова мимо. Смотреть на приведения
в тексте плана, они там видны явно.
Отдельно:EXPLAINбезANALYZEпоказывает оценку, а не факт. Расхождение оценки и реальности в десятки раз — само по себе диагноз, обычно как раз про статистику.