Indexes & Query Performance

Join, Sort, and Aggregation Algorithms

Physical operators trade startup, ordering, memory, repeated lookup, and spill behavior. Nested loop, hash, and merge joins—and hash versus sort/stream aggregation—are alternatives selected from input size, predicates, order, indexes, memory, and estimates.
  • Nested loop repeats inner work.
  • Hash join targets equijoins.
  • Merge join consumes compatible order.
  • Sort is blocking but reusable.
  • Hash aggregation stores groups.
  • Memory is per active operator/worker.
Algorithm comparison
OperatorInput requirementStrengthFailure mode
Nested loopAny join; efficient inner access helpsLow startup for tiny outer inputRepeated inner work
Hash joinHashable equalityLinear-style build/probe when fitSkew, batches, disk spill
Merge joinMerge-compatible equality/orderStreaming through sorted inputsSort cost and duplicate groups
Hash aggregateHashable group keysNo pre-sortToo many/wide groups spill
Sort/stream aggregateGrouped orderSmall streaming state after orderSort startup/spill if order absent
Same join, three physical shapes
Inspect memory and spill evidence
EXPLAIN (ANALYZE, BUFFERS)
SELECT o.customer_id, pc.category_id, sum(i.quantity * i.unit_price) AS revenue
FROM orders o
JOIN order_items i USING (order_id)
JOIN product_categories pc USING (product_id)
WHERE o.placed_at >= :from_time
GROUP BY o.customer_id, pc.category_id;
-- Look for loops, Sort Method/Disk, hash Buckets/Batches/Memory Usage, and temp I/O.

“Small build side” means the side’s actual filtered width and rows, not its base-table size. Projection and early filters matter. A cardinality miss can reverse the intended build/probe economics and cause an unexpected multi-batch hash.