DB Internals AtlasPostgreSQL 18.6 Home About

Parameter · Query Tuning / Other Planner Options

plan_cache_mode

Controls the planner's selection of custom or generic plan. Prepared statements can have custom and generic plans, and the planner will attempt to choose which is better. This can be set to override the default behavior.

  • Default: auto
  • Type: enum
  • Values: auto · force_generic_plan · force_custom_plan
  • Applies: Session (any user)

In plain words

A prepared statement can be planned fresh for every set of parameter values (a custom plan) or planned once with placeholders and reused (a generic plan). By default PostgreSQL tries custom plans five times, then switches to the generic plan if it is not noticeably worse. You can force either behaviour.

For DBAs and operators

In auto mode the first five executions use custom plans. From the sixth on, the generic plan is used if its estimated cost is lower than the average cost of the custom plans, which includes an estimate of their planning overhead. pg_prepared_statements shows generic_plans and custom_plans counters; EXPLAIN of a generic plan shows $1 instead of values:

PREPARE q(int) AS SELECT * FROM t WHERE a = $1;
SET plan_cache_mode = force_generic_plan;
EXPLAIN EXECUTE q(5);
--  Bitmap Heap Scan on t  (cost=5.84..608.94 rows=200 width=63)
--    Recheck Cond: (a = $1)

The classic problem: skewed data, where the generic plan (based on average selectivity) is terrible for some values, appears after exactly five fast executions, so a query becomes slow "after a while" through a driver that prepares statements (JDBC after prepareThreshold, PL/pgSQL, pgbouncer in transaction mode with prepared statements). force_custom_plan fixes that at the cost of planning every time; force_generic_plan saves planning time for very frequent, uniform queries. It also applies to PL/pgSQL statements, which are prepared internally.

How to change it

Any user can change it for their session with SET.

See it in context

Life of a query Planner cost model Wire protocol

Related parameters

cursor_tuple_fraction enable_partition_pruning default_statistics_target

All Query Tuning parameters