Conversation
Alena0704
marked this pull request as ready for review
September 17, 2026 19:54
Alena0704
marked this pull request as draft
September 17, 2026 20:18
Alena0704
force-pushed
the
fix-sort-memory-wanted-rel2
branch
from
September 17, 2026 20:38
fbb87f2 to
3e2d958
Compare
Alena0704
marked this pull request as ready for review
September 17, 2026 21:50
Alena0704
marked this pull request as draft
September 17, 2026 22:51
Alena0704
force-pushed
the
fix-sort-memory-wanted-rel2
branch
from
September 18, 2026 10:25
3e2d958 to
38f06d1
Compare
Alena0704
force-pushed
the
fix-sort-memory-wanted-rel2
branch
from
September 18, 2026 13:26
38f06d1 to
109232c
Compare
EXPLAIN ANALYZE prints "Memory wanted": how much memory an operator
needed to finish without writing to disk. Hash aggregation and hash
join fill it in, the sort does not: the code that did it was lost when
tuplesort was rewritten, and the call that hands the sort its
Instrumentation was left disabled under a GPDB_12_MERGE_FIXME. So a
query whose sort spilled gigabytes was advised to use less memory than
it already had.
This is a backport of the Greenplum 7 fix, greenplum-db/gpdb@fe0a9ddbdd
("re-implement explain analyze related code in tuplesort", #13590). It
counts the rows the sort was given and how much memory those rows took
when they were written out, and once the sort has spilled reports what
it would have needed to hold them in memory: the rows themselves plus
the array that points at them.
Changes against the original:
- PostgreSQL 14 sets up the per-sort state in tuplesort_begin_batch(),
so the counters are cleared there, next to growmemtuples, where the
original put them.
- The size of the array is computed in 64 bits; 1 << my_log2(n)
overflows an int once a sort is given more than 2^31 rows.
- Without an Instrumentation, tuplesort_get_stats() keeps reporting the
peak of the sort's memory context, as it did before.
- The original also reported the sort's memory as the node's executor
memory (execmemused), which adds an "Executor Memory" line under every
sort in EXPLAIN ANALYZE. That is a separate change and is left out.
A sort of 100k rows with statement_mem = '2MB':
Sort Method: external merge Disk: 21696kB
Memory wanted: 10885kB (nothing was printed before)
Backported-by: Alena Rybakina <alenka.rybakina@gmail.com>
In a parallel sort every worker sorts its own share of the rows, but only the leader's sort was connected to the node's Instrumentation, so "Memory wanted" ignored whatever the workers spilled. Keep the estimate in the sort state as well and hand it over through the statistics the workers already store in shared memory; the leader reports the largest of them.
Operators that need a lot of memory each get a share of statement_mem. Incremental Sort did not: it always sized its sorts from work_mem, and it was counted among the cheap operators that get 100kB, so it was also left out when the memory need of the whole statement was worked out. Raising statement_mem therefore did nothing for an Incremental Sort that spilled. 2M rows in five groups, statement_mem = '64MB': before: Sort Method: external merge Average Disk: 16102kB after: Sort Method: quicksort Average Memory: 41738kB Give the node its share, and count it as an operator that needs memory.
Incremental Sort sorts the rows group by group, each group in a sort of its own, and none of those figures reached EXPLAIN ANALYZE. The plan showed the work files the node had written, but said nothing about the memory it took, nor about the memory it was short of: before: Executor memory: 2045K bytes avg x 3x(0) workers, ... after: Executor memory: ... Work_mem: 1622K bytes max, 42775K bytes wanted. Report the busiest group, in the leader and in parallel workers alike, and record that the node wrote work files. Each group is measured on its own, since the sort clears its counters whenever it starts the next one, so the advice does not grow with the number of groups.
Alena0704
force-pushed
the
fix-sort-memory-wanted-rel2
branch
from
September 18, 2026 14:53
109232c to
8a9ade9
Compare
Alena0704
marked this pull request as ready for review
September 18, 2026 18:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
"Memory wanted" in EXPLAIN ANALYZE is built from instrument->workmemwanted, the work_mem an operator needed to avoid spilling. Hash aggregation and hash join set it, but the sort no longer does: a sort that spilled gigabytes to disk contributed nothing, and EXPLAIN advised less memory than the query had already been given.
This is a backport of the Greenplum 7 fix, greenplum-db/gpdb@fe0a9ddbdd (#13590). Cloudberry forked before it landed, so the call that hands the sort its Instrumentation is still disabled in nodeSort.c under a GPDB_12_MERGE_FIXME; the backport enables it again and is adapted to PostgreSQL 14. A second commit extends it to parallel sort workers: each worker hands its estimate over through the statistics it already keeps in shared memory, and the leader reports the largest one.
Reproduction :
Before : the sort writes to disk and says nothing about it — no
Memory wantedline at all, and the slice only reports how muchwork_memit got.After: the sort reports what it would have needed.
With
statement_mem = '10MB'the sort no longer spills, and there is nothing left to ask for.While testing the sort fix I found that Incremental Sort mishandles memory in two related ways, so this PR carries two more commits:
Reproduction :
Before
Raising statement_mem to 64MB changes nothing. Each group is measured on its own, so the advice does not grow with the number of groups.:
After
inc5, statement_mem = '2MB' — the node stays within its share and says what it needs:
inc10 — twice the data and twice the groups, but groups of the same size, so the advice is the same:
Give inc5 the 42MB it asked for and nothing is written to disk.
The busiest group peaks at 41789kB against the 42775kB predicted — within 3%.
Type of Change
Breaking Changes
Test Plan
make installcheckmake -C src/test installcheck-cbdb-parallelImpact
Performance:
User-facing changes:
Dependencies:
Checklist
Additional Context
CI Skip Instructions