pgconfigurator
pgconfigurator

Gather Merge

Appears in EXPLAIN asGather Merge

Collects rows from workers while preserving sorted order.

What it is

A Gather Merge collects rows from parallel workers like Gather, but each worker produces sorted output and the node merges those streams to keep the global ordering.

When the planner picks it

For parallel plans that must preserve an ORDER BY — e.g. a parallel sort or an ordered index scan under parallelism.

Is it good or bad?

Lets ORDER BY benefit from parallelism. Same caveat as Gather: under-launched workers reduce the speedup.

In depth

Order-preserving parallelism

Gather Merge is Gather with a guarantee: each worker produces a sorted stream and the node merges those streams to preserve the global ordering. The leader pulls one row at a time from whichever worker's next row is smallest, just like Merge Join does with two inputs.

That's how a parallel ORDER BY works: each worker sorts (or scans an indexed range) its slice; Gather Merge merges the slices.

What to check

The numbers to read are the same as for plain Gather:

Gather Merge  (actual rows=1000000 loops=1)
  Workers Planned: 4
  Workers Launched: 2

Workers Launched < Workers Planned means the worker pool was exhausted — either by max_parallel_workers / max_worker_processes, or by other concurrent parallel queries — so part of the work fell back to the leader.

Per-child counters under Gather Merge are typically per-worker averages with loops reflecting the number of participants, so totals can look small until you multiply.

Choosing Gather Merge vs Gather

The planner picks Gather Merge automatically when the result must keep an order (an upstream ORDER BY, or a merge / window operation that needs sorted input). It's a little more expensive than plain Gather because of the merge step, so for unordered results the planner uses Gather.

What the analyzer flags here

  • Parallel under-use — fewer workers launched than planned

Paste a plan into the analyzer →

Settings that influence it

max_parallel_workers_per_gathermax_parallel_workers

How we tune these →

See also