#Симптом и границы применимости
После создания индекса PostgreSQL продолжает выбирать Seq Scan. Это не всегда ошибка: полный просмотр быстрее для небольшой таблицы или запроса, возвращающего значительную долю строк; решают статистика, фильтр, порядок колонок и реальная стоимость.
#Как отличить возможные причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Таблица малаПланировщику дешевле прочитать несколько страниц подряд. | Seq Scan при малом объёме | Оставить без изменения |
| Малая селективностьWHERE выбирает большую долю таблицы. | Высокое число ожидаемых строк | Сверить реальные параметры |
| Индекс не подходитФильтр использует выражение/каст или не ведущую колонку составного индекса. | Index Cond отсутствует | Скорректировать запрос и индекс после теста |
#Пошаговая диагностика и безопасное исправление
- 1. Запишите точный запрос и ожидаемый объёмВозьмите SQL из приложения с реальными параметрами, обезличьте значения и зафиксируйте скорость. Не сравнивайте EXPLAIN WHERE id=1 с фактическим запросом WHERE status=active — планы могут отличаться.
- 2. Посмотрите план без запуска тяжёлого запросаВ psql выполните EXPLAIN для SELECT и изучите Seq Scan, rows, cost и Filter. Seq Scan сам по себе не доказывает ошибку; для маленькой таблицы он может быть оптимальным.SQLКомандаpsql; чтение плана. Подставьте реальный запрос; значения и таблица — условные.
EXPLAIN SELECT id FROM app.orders WHERE status='new';
- 3. Проверьте определение индексаВ каталоге pg_indexes найдите созданный индекс и его определение. В составном индексе порядок колонок важен; индекс на created_at не обязан ускорить WHERE status=...
- psql, только чтениеSQLКомандаpsql, только чтение.
SELECT indexname, indexdef FROM pg_indexes WHERE schemaname='app' AND tablename='orders';
- 4. Оцените размер таблицы и статистикуСравните reltuples, last_analyze и n_mod_since_analyze с реальной нагрузкой. Статистика оценочная, а расхождение с распределением по статусам может менять выбор плана.
- psql; сведения оценочныеSQLКомандаpsql; сведения оценочные.
SELECT relname, n_live_tup, last_analyze, last_autoanalyze FROM pg_stat_user_tables WHERE schemaname='app' AND relname='orders';
- 5. Проверьте типы условий и преобразованияСравните тип колонки и параметра: явный CAST самой индексируемой колонки или функциональное выражение может мешать обычному индексу. Найдите такие участки в реальном WHERE и JOIN до правок.
- 6. Сравните план после ANALYZE на тестовой копииПри устаревшей статистике выполните ANALYZE таблицы на тестовой копии и снова EXPLAIN. На рабочей базе не выключайте enable_seqscan глобально: можно ухудшить другие запросы.SQLС осторожностьюПрава администратораpsql на тестовой базе; обновляет статистику оптимизатора, не принуждает использовать индекс.
ANALYZE app.orders;Команда может изменить состояние системы или её настройки. Проверьте параметры и последствия перед запуском.
- 7. Оцените фактическую выгоду только на тестеДля безопасного SELECT на тестовой базе допускается EXPLAIN (ANALYZE, BUFFERS), но он выполняет запрос. Сравните реальное время и число буферов на сопоставимых данных, а не только стоимость из EXPLAIN.
- 8. Оставьте планировщику разумный выборЕсли Seq Scan объективно быстрее, не меняйте ничего. Если план плохой, согласуйте исправление запроса или подходящий индекс с учётом дискового места и стоимости INSERT/UPDATE.
#Как проверить, что проблема устранена
На сопоставимом тесте запрос стал быстрее либо доказано, что Seq Scan оптимален; дополнительные индексы не нарушили скорость записи.
#Если исправление не помогло
Если оценки расходятся с действительностью, проверьте корреляцию столбцов, распределение значений и настройки планировщика; не применяйте глобальные отключения сканирования.