14.6. Автоподготовленные операторы

В Postgres Pro Enterprise реализован режим автоподготовки операторов, в котором часто используемые операторы могут неявно подготавливаться, что позволяет оптимизировать затраты на их компиляцию и разбор при каждом последующем выполнении.

По сравнению с применением явно подготовленных операторов, этот режим даёт чуть менее значительное ускорение, но позволяет получать подготовленные планы там, где явные команды PREPARE не поддерживаются. Например, он может быть полезен, когда применяется pgbouncer (в любом режиме, кроме session), когда используются распределённые секционированные таблицы или когда в применяемых приложениях баз данных не предусмотрено выполнение подготовленных операторов.

По умолчанию режим автоподготовки отключён. Чтобы включить его, присвойте ненулевое значение переменной конфигурации autoprepare_threshold, которая определяет, сколько раз должен выполниться оператор, чтобы он был автоматически подготовлен. После того как один запрос с различными буквальными значениями повторяется заданное количество раз, Postgres Pro строит общий план для этого запроса, заменяя все константы параметрами. Общий план для запроса будет выбираться, если ожидаемое время выполнения этого плана окажется меньше, чем среднее время выполнения специализированных планов. Так же, как и с явно подготавливаемыми операторами, при изменениях в каталоге общие планы аннулируются.

Когда эта функциональность включена, автоподготовка может охватывать запросы, передаваемые как по простому, так и по расширенному протоколу. Расширенный протокол поддерживает передачу параметризованных запросов, а автоподготовка таких запросов связана с меньшими издержками. С другой стороны, запросы, поступающие по разным протоколам, могут иметь разный характер, а для некоторых видов запросов автоподготовка неэффективна. В связи с этим параметр autoprepare_for_protocol позволяет включать/отключать автоподготовку операторов на уровне протоколов.

Если ваше приложение выполняет множество различных операторов, в результате автоподготовки они могут занимать много памяти, если не ограничить размер кеша. Это особенно важно при большом количестве активных клиентов, так как кеш автоподготовленных операторов существует в рамках обслуживающего процесса. Чтобы избежать раздувания кеша, вы можете сделать следующее:

  • Ограничить число автоподготавливаемых операторов в рамках одного процесса, воспользовавшись параметром autoprepare_limit. Это рекомендуется, когда нагрузку создаёт множество простых запросов.

  • Ограничить объём памяти, который могут занимать автоподготовленные операторы в обслуживающем процессе, воспользовавшись параметром autoprepare_memory_limit. Это может повлечь некоторые издержки, связанные с вычислением объёма кеша автоподготовленных операторов, поэтому данный вариант рекомендуется только для нагрузки со сложными запросами, когда ограничение количества автоподготовленных операторов может быть неэффективным.

В обоих случаях наиболее часто выполняемые запросы будут находиться в памяти под контролем LRU. Если устанавливаются оба параметра, фактически будет действовать ограничение, которое достигается первым.

Обратите внимание, что кеш автоматически подготовленных операторов полностью очищается при выполнении следующих команд:

  • DISCARD PLANS

  • DISCARD ALL

  • Любая команда ALTER SYSTEM...

  • Любая команда SET var, как отдельная, так и внутри других команд. Например:

    ALTER TABLE test ALTER COLUMN a SET STORAGE PLAIN
  • Любая команда DDL, поддерживающая событийные триггеры, например CREATE/DROP TABLE.

Вы можете просмотреть все автоподготовленные операторы в текущем сеансе, обратившись к системному представлению pg_autoprepared_statements. В нём показывается текст исходного запроса, типы выделенных параметров, заменяющих буквальные значения, и счётчик выполнений запроса.