The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Find parallel nodesEXPLAIN (COSTS, VERBOSE) SELECT count(*) FROM app.orders;View examples
Measure workers launchedEXPLAIN (ANALYZE, SUMMARY) SELECT count(*) FROM app.orders;View examples
Show worker detailEXPLAIN (ANALYZE, VERBOSE) SELECT count(*) FROM app.orders;View examples
Set a local worker capSET LOCAL max_parallel_workers_per_gather = 4;View examples
Inspect worker settingsSELECT name, setting FROM pg_settings WHERE name LIKE 'max_parallel%';View examples
Inspect setup costSHOW parallel_setup_cost;View examples
Inspect table thresholdSHOW min_parallel_table_scan_size;View examples
Label a function safeALTER FUNCTION app.net_amount(numeric, numeric) PARALLEL SAFE;View examples
Label a function restrictedALTER FUNCTION app.read_backend_state() PARALLEL RESTRICTED;View examples
Disable parallel useALTER FUNCTION app.write_audit(text) PARALLEL UNSAFE;View examples
Disable parallelism locallySET LOCAL max_parallel_workers_per_gather = 0;View examples
Check transaction isolationSHOW transaction_isolation;View examples
Enable JIT locallySET LOCAL jit = on;View examples
Inspect the JIT thresholdSHOW jit_above_cost;View examples
Disable JIT locallySET LOCAL jit = off;View examples
Show JIT availabilitySHOW jit_provider;View examples
Track nondefault plan settingsEXPLAIN (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

01

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.

Inspect worker usage on an aggregate
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.

Back to quick reference ↑
02

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.

Test a per-session worker ceiling
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.

Back to quick reference ↑
03

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.

Compare a plan under temporary cost assumptions
BEGIN;
SET LOCAL parallel_setup_cost = 500;
SET LOCAL parallel_tuple_cost = 0.05;
EXPLAIN (SETTINGS) SELECT sum(total) FROM app.orders;
ROLLBACK;
Back to quick reference ↑
04

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.

Mark a pure SQL helper parallel safe
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.

Back to quick reference ↑
05

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.

Verify the isolation level before a benchmark
SELECT current_setting('transaction_isolation') AS isolation,
       current_setting('max_parallel_workers_per_gather') AS per_gather;
Back to quick reference ↑
06

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.

Compare JIT within one transaction
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.

Back to quick reference ↑
07

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.

Inspect parallel capacity and JIT availability
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;
Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. PostgreSQL Global Development GroupParallel Querypostgresql.org
  2. PostgreSQL Global Development GroupWhen Can Parallel Query Be Used?postgresql.org
  3. PostgreSQL Global Development GroupParallel Planspostgresql.org
  4. PostgreSQL Global Development GroupParallel Safetypostgresql.org
  5. PostgreSQL Global Development GroupJust-in-Time Compilationpostgresql.org
  6. PostgreSQL Global Development GroupWhen to JITpostgresql.org
  7. PostgreSQL Global Development GroupResource Consumption Settingspostgresql.org
  8. 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.

Share feedback