Комментарий пользователя
Мы создали все необходимые индексы для таблицы, но PostgreSQL упорно их игнорирует. При выполнении точечного запроса планировщик почему-то все равно выбирает полное сканирование диска (Sequential Scan), из-за чего выборка зависает. Почему база данных не видит созданные индексы?
Ответ специалиста
Добрый день, Андрей! Дело в том, что наличие индекса в базе данных не гарантирует, что оптимизатор выберет именно его. PostgreSQL строит план выполнения на основе внутренней модели затрат и выбирает тот путь, который по расчетам выглядит дешевле. Если индексы созданы корректно, но СУБД переходит к полному последовательному сканированию таблицы (Seq Scan), это может происходить по нескольким причинам.
Устаревшая или неполная статистика
Планировщик оценивает стоимость запроса на основе статистических данных: количества строк, числа страниц на диске и распределения значений в колонках. Если вы недавно импортировали, реплицировали, массово добавили или удалили большой объем данных, статистика становится неактуальной. База данных строит неверные предположения о количестве строк, занижает стоимость последовательного чтения и игнорирует индекс.
Для исправления ситуации нужно обновить статистику для таблицы вручную, чтобы оптимизатор увидел реальное распределение данных:
ANALYZE users;
Если перед этим выполнялось массовое удаление строк, эффективнее запустить комбинированную команду для очистки страниц и одновременного сбора свежей статистики:
VACUUM ANALYZE users;
Несоответствие типов данных или функций
Индекс B-Tree может игнорироваться, если в условии WHERE тип передаваемого параметра не совпадает с типом колонки в базе (происходит неявное приведение типов), либо если поле обернуто в функцию, под которую не был создан специальный индекс.
Чтобы проверить работу планировщика, запустите запрос с командой проверки реального плана:
EXPLAIN ANALYZE
SELECT id, name FROM users WHERE email = 'admin@example.com';
Затем сравните показатели в выводе:
rowsв блоке оценки стоимости — сколько строк планировщик ожидал найти.rowsв блокеActual time— сколько строк было получено на самом деле.
Если эти значения сильно различаются (например, ожидалась 1 строка, а обработано 100 000), это прямое подтверждение того, что статистика устарела. После выполнения команды ANALYZE планировщик пересчитает cost и автоматически переключится на быстрый Index Scan.
Больше про оптимизацию PostgreSQL читайте в нашем материале.