В Postgres 19 наконец-то появится то, что сообщество считало невозможным — «советы» по плану запросов. Да-да, именно «советы», а не хинты, потому что Postgres так не делает. Теперь делает. За фичу отвечают два новых модуля — pg_plan_advice и pg_stash_advice. Их автор — Роберт Хаас, который ещё в 2010 году на легендарной дискуссии в рассылке pgsql-performance утверждал, что DBА нужен запасной люк для тех 0.1% запросов, которые не починить настройкой статистики.
Сообщество годами было против хинтов. Аргументы железные: они ломают планы при обновлениях, мешают улучшать оптимизатор, создают ад в поддержке. Даже Том Лэйн признавал, что не видел годной схемы, но не говорил, что её не может быть. А Джош Беркус настаивал: хинты не должны вшиваться в SQL-код, иначе потом не отклеишь. Хаас всё это учёл.
pg_plan_advice не заменяет планировщик, а ограничивает пространство его поиска. Совет задаётся через GUC или хранится в отдельном stash-контейнере по идентификатору запроса. Сам SQL остаётся чистым. Если совет устарел или невыполним — планировщик не падает, а просто помечает узел как Disabled и выбирает лучший из оставшихся вариантов. Всё деградирует мягко.
Синтаксис советов выразительный. Можно управлять методами сканирования (INDEX_SCAN, SEQ_SCAN и даже DO_NOT_SCAN), порядком соединений (JOIN_ORDER со строгими скобками и гибкими фигурными), методами джойнов (HASH_JOIN, NESTED_LOOP_PLAIN) и параллельным выполнением (GATHER, NO_GATHER). Планировщик сам умеет выдавать совет, воспроизводящий текущий план — просто добавьте PLAN_ADVICE в EXPLAIN.
Для продакшена придуман pg_stash_advice. Создаёте именованный stash в разделяемой памяти, кладёте туда советы по query_id, активируете через GUC — и всё, каждый такой запрос получает нужный план. Можно привязать к сессии, роли или целой базе. Советы сохраняются на диск и переживают перезапуск. А главное — их можно убрать одной командой, не трогая код приложения.
Хаас сделал фичу, которая закрывает почти все старые претензии. Советы не зашиты в SQL, не ломают планировщик, сами себя документируют, а EXPLAIN честно показывает, что сработало, что нет, а где был конфликт. Чего пока нет — управления агрегацией, сортировкой и операциями UNION. И небольшой penalty на производительность при каждом выполнении совета. Это скальпель, а не кувалда.
Сообщество 15 лет говорило «никогда», а в итоге получило едва ли не лучшую реализацию «советов» среди всех СУБД. Больше не надо дёргать enable_seqscan или вставлять OFFSET 0 в надежде, что планировщик сделает по-своему. Postgres наконец-то дал DBA легальный, безопасный и временный способ сказать: «Нет, дорогой, давай вот так».