PostgreSQL Hash Aggregation Spills Groups in Batches
A HashAggregate node does not require every group to remain in memory for the full query. If the hash table grows past its executor memory limit, PostgreSQL can retain active groups in memory while routing tuples for additional groups into temporary batches. Those batches are processed later, so hash aggregation can complete without allowing an unexpectedly large group set to consume unbounded memory. This behavior matters because the planner chooses an aggregation strategy from estimates, while the executor has to handle the rows that actually arrive. A cardinality estimate can be imperfect, data can change after statistics were collected, and a grouping key can produce far more distinct groups than a small sample suggests. Disk-backed hash aggregation provides an execution path for those cases.