Статистика и подсказки планировщику PostgreSQL: что чинить
Если PostgreSQL выбирает медленный план, подсказка может замаскировать проблему, но не устранить её. В PostgreSQL 16 сначала сравните оценку строк с фактом, обновите статистику и проверьте корреляции — и только потом решайте, нужна ли внешняя подсказка.

В PostgreSQL 16 запрос может читать таблицу целиком, хотя подходящий индекс есть, или выбрать неудачный порядок соединения. Часто причина не в том, что планировщик «сломался», а в неверной оценке числа строк. Подсказка способна заставить его выбрать другой план, но если статистика устарела или не описывает связь между столбцами, проблема вернётся при изменении данных. Разберём, что проверять первым и в каких случаях оправдана внешняя подсказка.
Сначала найдите расхождение в плане
Начните с плана, а не с принудительного выбора индекса. Для PostgreSQL 16 используйте EXPLAIN (ANALYZE, BUFFERS) на конкретном запросе. Команда с ANALYZE действительно выполняет запрос: осторожно проверяйте её на изменяющих данных операциях и в системе, где запуск может создать нагрузку.
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*)
FROM orders
WHERE region = 'north' AND status = 'paid';
В выводе сравните rows — оценку планировщика — с actual rows. Например, если узел рассчитывал прочитать несколько десятков строк, а нашёл десятки тысяч, это повод проверить статистику и условия фильтра. При нескольких циклах (loops) фактическое число строк в выводе обычно указано в среднем на цикл; для оценки общего объёма учитывайте и число циклов.
Смотрите и на соседние признаки: сколько строк отбрасывает фильтр, сколько страниц прочитано и где план переходит к соединению таблиц. Большая разница оценок — диагностический сигнал, а не доказательство одной конкретной причины. Само по себе наличие последовательного сканирования тоже не означает ошибку: для большой доли таблицы оно может быть дешевле чтения через индекс.
Оценка кардинальности — прогноз планировщика о том, сколько строк выдаст узел плана. От этого прогноза зависят выбор доступа к таблице и порядок соединений.
Четыре рычага — от простого к рискованному
| Рычаг | Когда помогает | Цена и ограничение |
|---|---|---|
Обычный ANALYZE | Данные заметно изменились, статистика не успела обновиться. | Сбор статистики требует ресурсов; сам по себе не описывает все связи столбцов. |
| Расширенная статистика | Фильтры по нескольким столбцам одной таблицы связаны между собой. | Нужно выбрать подходящий вид статистики; она не решает все оценки, в частности не заменяет статистику для соединений таблиц. |
| Повышенная цель статистики столбца | Распределение значений сложное, а стандартной выборки не хватает для оценки. | Сбор и хранение статистики могут занять больше ресурсов; сначала проверьте эффект на нужном столбце. |
| Внешние подсказки | План нужно временно стабилизировать, а причины плохой оценки уже исследованы. | Это дополнительное расширение с отдельными требованиями к версии и эксплуатации; подсказка может устареть вместе с данными. |
Обновите обычную статистику
PostgreSQL собирает статистику автоматически, но после большой загрузки или резкой смены распределения проверьте, успела ли она обновиться. Для конкретной таблицы статистику можно собрать командой:
ANALYZE orders;
Затем повторите план и сравните оценки. Если планировщик по-прежнему сильно ошибается на фильтре по одному столбцу, проверьте его запись в системном представлении pg_stats: там доступны, среди прочего, распространённые значения и оценка числа различных значений. Это помогает заметить перекос, но не заменяет измерение запроса.
Добавьте расширенную статистику для связанных столбцов
Предположим, в таблице orders значения region и status связаны: оплаченные заказы распределены по регионам не так, как все заказы. Обычная статистика по каждому столбцу отдельно может дать плохой прогноз для условий, где они используются вместе. В PostgreSQL 16 можно собрать статистику по сочетанию этих столбцов:
CREATE STATISTICS orders_region_status_stats (dependencies, mcv)
ON region, status
FROM orders;
ANALYZE orders;
dependencies описывает зависимости между столбцами, а mcv — распространённые сочетания значений. Выбирайте виды статистики под конкретный характер данных, а не добавляйте все варианты «на всякий случай». Расширенная статистика относится к столбцам одной таблицы и не является универсальным способом исправить оценку соединения разных таблиц.
Увеличивайте цель статистики точечно
Если проблема связана с распределением одного столбца, попробуйте повысить для него цель статистики, а не менять настройку сразу для всей базы:
ALTER TABLE orders
ALTER COLUMN region SET STATISTICS 500;
ANALYZE orders;
Число здесь — выбранная цель для конкретного столбца, а не универсальная рекомендация. После повторного замера оставьте изменение только тогда, когда оно улучшает оценки и план без неприемлемой цены по времени анализа и объёму статистики. Если улучшения нет, возвращайтесь к причине расхождения, а не повышайте значение вслепую.
Когда оправданы подсказки
В ядре PostgreSQL нет встроенного синтаксиса подсказок вида «для этого запроса обязательно используй такой-то индекс». Для принудительного выбора плана используют сторонние решения, например расширение pg_hint_plan. Его наличие и совместимость нужно проверять для конкретной версии PostgreSQL и сборки: расширение не становится частью ядра от одного упоминания в SQL.
Подсказка уместна как временная страховка, если вы измерили запрос, проверили актуальность статистики, нашли приемлемый альтернативный план и понимаете, почему планировщик выбирает иначе. Но у такой страховки есть обслуживание: после роста таблицы, смены распределения или обновления PostgreSQL принудительный план может стать хуже. Кроме того, зависимость от расширения влияет на установку, обновление и перенос конфигурации между окружениями.
Если план плох из-за неверной оценки строк, принудительный выбор плана лечит симптом. Сначала исправьте данные, на которых строится прогноз, — иначе подсказка превратится в ещё одну настройку, за которой нужно следить.
Параметры планировщика вроде enable_nestloop полезны для диагностики: в контролируемом тесте можно проверить, изменится ли план без определённого способа соединения. Это не точечные подсказки для одного запроса и не хорошая замена анализу статистики. Не переносите экспериментальную настройку в постоянную конфигурацию только потому, что один запрос ускорился.
Что обычно ломается
- Статистику собрали, но оценка не изменилась. Проверьте, что анализировали нужную таблицу и что расхождение связано именно с теми столбцами. Для связанной пары условий может понадобиться расширенная статистика.
- Подняли цель статистики на всех столбцах. Это увеличивает цену сбора данных без гарантии улучшить планы. Начинайте с конкретного столбца и сравнивайте замеры до и после.
- Отключили тип соединения в конфигурации. Быстрый план одного запроса может ухудшить другие. Используйте переключение как эксперимент, затем ищите причину ошибочного выбора.
- Оставили подсказку после изменения данных. План, подходивший небольшой таблице или прежнему распределению, может проиграть после роста нагрузки. Повторяйте проверку на репрезентативных данных.
Что делать дальше
Выберите один медленный запрос и сохраните его план с EXPLAIN (ANALYZE, BUFFERS) вместе с условиями замера. Найдите первый узел, где оценка строк заметно расходится с фактом; проверьте свежесть статистики и связь фильтруемых столбцов. После каждого изменения повторяйте запрос на сопоставимых данных и сравнивайте не только время, но и оценки строк, чтение страниц и устойчивость плана. Инвалидация кэша и настройка пула соединений — отдельные темы: здесь разбирали именно выбор плана по статистике.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: PostgreSQL 16: Planner Statistics, pg_hint_plan: официальный репозиторий проекта
Частые вопросы
PostgreSQL сам обновляет статистику или нужно запускать ANALYZE вручную?
Почему после ANALYZE план не изменился?
Можно ли заставить PostgreSQL использовать индекс подсказкой?
Безопасно ли запускать EXPLAIN ANALYZE в продакшене?
Что делать, если у меня PostgreSQL другой версии?
Как понять, что подсказка не стала причиной новой проблемы?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.