The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Find parallel nodes | EXPLAIN (COSTS, VERBOSE)
SELECT count(*)
FROM app.orders; | View examples |
| Measure workers launched | EXPLAIN (ANALYZE, SUMMARY)
SELECT count(*)
FROM app.orders; | View examples |
| Show worker detail | EXPLAIN (ANALYZE, VERBOSE)
SELECT count(*)
FROM app.orders; | View examples |
| Set a local worker cap | SET LOCAL max_parallel_workers_per_gather = 4; | View examples |
| Inspect worker settings | SELECT name, setting
FROM pg_settings
WHERE name LIKE 'max_parallel%'; | View examples |
| Inspect setup cost | SHOW parallel_setup_cost; | View examples |
| Inspect table threshold | SHOW min_parallel_table_scan_size; | View examples |
| Label a function safe | ALTER FUNCTION app.net_amount(numeric, numeric) PARALLEL SAFE; | View examples |
| Label a function restricted | ALTER FUNCTION app.read_backend_state() PARALLEL RESTRICTED; | View examples |
| Disable parallel use | ALTER FUNCTION app.write_audit(text) PARALLEL UNSAFE; | View examples |
| Disable parallelism locally | SET LOCAL max_parallel_workers_per_gather = 0; | View examples |
| Check transaction isolation | SHOW transaction_isolation; | View examples |
| Enable JIT locally | SET LOCAL jit = on; | View examples |
| Inspect the JIT threshold | SHOW jit_above_cost; | View examples |
| Disable JIT locally | SET LOCAL jit = off; | View examples |
| Show JIT availability | SHOW jit_provider; | View examples |
| Track nondefault plan settings | EXPLAIN (SETTINGS, SUMMARY)
SELECT sum(total)
FROM app.orders; | View examples |
Parallel query and JIT target different bottlenecks: parallel plans divide eligible work among processes, while JIT compiles expressions for sufficiently expensive CPU-bound plans. Both add startup overhead, are cost-driven rather than guarantees, and should be evaluated with representative queries and concurrency.
Step by step
Detailed examples
Recognize leader and worker behavior in plans
A Gather or Gather Merge node launches workers when capacity is available; the leader also participates unless disabled, but may spend most of its time consuming tuples. EXPLAIN ANALYZE reports workers actually launched, which can be lower than planned when global worker pools are busy.
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT tenant_id, sum(total)
FROM app.orders
GROUP BY tenant_id; Note: Run only against a safe read-only workload; compare Workers Planned and Workers Launched.
Understand all worker ceilings
max_parallel_workers_per_gather caps one plan node, max_parallel_workers caps parallel-query workers cluster-wide, and max_worker_processes caps the broader worker pool. Raising only the per-query setting cannot create capacity. More workers also increase CPU, memory, and I/O pressure, and each worker may use work_mem independently.
BEGIN;
SET LOCAL max_parallel_workers_per_gather = 4;
EXPLAIN (ANALYZE, SETTINGS) SELECT avg(total) FROM app.orders;
ROLLBACK; Note: SET LOCAL disappears at transaction end; it does not override cluster-wide capacity.
Change parallel cost settings only after measuring
The planner compares parallel setup and tuple-transfer costs with estimated savings. Lowering costs can expose experiments but may over-parallelize short queries. min_parallel_table_scan_size and min_parallel_index_scan_size are planner thresholds, not eligibility switches, and repeated workers scale those thresholds nonlinearly.
BEGIN;
SET LOCAL parallel_setup_cost = 500;
SET LOCAL parallel_tuple_cost = 0.05;
EXPLAIN (SETTINGS) SELECT sum(total) FROM app.orders;
ROLLBACK; Label custom functions truthfully
Functions are UNSAFE by default unless labeled otherwise. SAFE permits worker execution, RESTRICTED confines execution to the leader below Gather, and UNSAFE disables parallel plans for the query. Mislabeling code that touches sequences, backend-local state, temporary tables, or unsafe extensions can produce errors or wrong behavior.
CREATE OR REPLACE FUNCTION app.net_amount(numeric, numeric)
RETURNS numeric
LANGUAGE sql IMMUTABLE PARALLEL SAFE
RETURN $1 - $2; Note: Only use PARALLEL SAFE after auditing every operation and called function; function ownership is required to alter it.
Know when PostgreSQL suppresses parallel query
Parallel query is unavailable in several contexts, including commands that write data, serializable transactions, and queries invoking parallel-unsafe functions. A query beneath a data-modifying CTE also cannot use parallel execution. Even an eligible query may stay serial when estimates say worker overhead is not worthwhile.
SELECT current_setting('transaction_isolation') AS isolation,
current_setting('max_parallel_workers_per_gather') AS per_gather; Use JIT for expensive CPU-bound work, not latency-sensitive trivia
JIT activates when estimated total cost exceeds jit_above_cost and a provider is available. Higher thresholds separately control inlining and expensive optimization; decisions occur at plan time, including for generic prepared plans. Compilation overhead commonly hurts short OLTP queries.
BEGIN;
SET LOCAL jit = on;
SET LOCAL jit_above_cost = 10000;
EXPLAIN (ANALYZE, SETTINGS) SELECT sum(total * tax_rate) FROM app.order_lines;
ROLLBACK; Note: Look for a JIT section and compare total execution across repeated representative runs.
Benchmark end-to-end under realistic concurrency
A faster isolated query can reduce throughput if many sessions compete for workers or memory. Compare planning, JIT generation, execution, temp I/O, and worker availability, and remember standbys can execute parallel read queries but have their own worker limits and replay pressure. Avoid globally forcing plans from a single sample.
SELECT name, setting, unit, source
FROM pg_settings
WHERE name IN ('max_worker_processes', 'max_parallel_workers', 'max_parallel_workers_per_gather', 'jit', 'jit_provider')
ORDER BY name; Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- PostgreSQL Global Development GroupParallel Querypostgresql.org
- PostgreSQL Global Development GroupWhen Can Parallel Query Be Used?postgresql.org
- PostgreSQL Global Development GroupParallel Planspostgresql.org
- PostgreSQL Global Development GroupParallel Safetypostgresql.org
- PostgreSQL Global Development GroupJust-in-Time Compilationpostgresql.org
- PostgreSQL Global Development GroupWhen to JITpostgresql.org
- PostgreSQL Global Development GroupResource Consumption Settingspostgresql.org
- PostgreSQL Global Development GroupQuery Planning Settingspostgresql.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



