Repository navigation
Conversation
Parallel workers on the same segment share a slot in the node summary. A later worker can overwrite that slot after an accumulator has selected an earlier worker as its winner. As a result, EXPLAIN ANALYZE can report rows, timing, loops, and memory statistics from the last processed worker instead of the selected worker. Copy the winner's instrumentation from its stable received statistics message rather than from the reusable per-segment summary slot.
|
There is a bug in I suggest to do it in a separate PR because it's logically independent fix. |
|
The winner-statistics fix looks correct, but allstat still loses parallel-worker statistics: four QEs execute the scan, yet only two records appear. Workers on the same segment overwrite the same ns->insts slot, leaving only the last worker’s statistics for each segment. reproduction on a cluster with two primary segments: |
Yes, I mentioned this problem in my comment above. I suggest to patch it in an independent PR -- look at the comment here #2209 (comment). |
Overview
cdbexplain_depositStatsToNode()receives execution statistics from the executors and uses them to populate the dispatcher’s Instrumentation object.For each plan node, the function works with four related objects:
rshis theCdbExplain_StatHdrfor the current executor statistics message. It contains the segment index, the array of per-node statistics, worker-level statistics, and extra-text metadata.rsipoints to theCdbExplain_StatInstfor the current plan node insidersh:It identifies the statistics of one specific executor or parallel worker. The received message remains valid while the statistics are being deposited, so rsi is a stable pointer to that worker’s record.
nsis theCdbExplain_NodeSummaryallocated for the current plan node and attached to the dispatcher’s Instrumentation. It contains aggregate statistics and an insts array with one slot per segment.nsipoints to the entry inns->instscorresponding torsh->segindex:Unlike
rsi,nsiidentifies a segment slot, not a particular worker.The function iterates over all received executor statistics messages:
For non-parallel execution, there is normally one statistics record per segment, so copying
rsiinto the segment’snsislot is unambiguous.With parallel execution, several workers can run on the same segment. All of their messages have the same
rsh->segindex, so they resolve to the same nsi address:Each
*nsi = *rsitherefore overwrites the statistics copied from the previous worker on that segment.At the same time, the function maintains several accumulators. When an accumulator finds a new maximum, it records both:
rsimax: the stable receivedCdbExplain_StatInstof the winning worker.nsimax: the per-segmentns->instsslot into which that worker was copied.The problem is that
rsimaxcontinues to identify the selected worker, whilensimaxcan subsequently be overwritten by another worker from the same segment.After all messages have been processed, the old code copied the winner’s instrumentation from nsimax:
Consequently, the accumulator could select one worker as the winner, but the displayed rows, loops, timing, filtering, and memory values could come from a later worker that reused the same segment slot.
In other words, nsimax identifies the winner’s segment slot, but it does not reliably identify the winner itself.
Reproduction
The issue can be reproduced with multiple parallel workers per segment:
The same you can observe if you use PostgreSQL planner:
What does this PR do?
Copy the winner's instrumentation from its stable received statistics message (
rsi) rather than from the reusable per-segment summary slot (nsi).Type of Change
Test Plan
make installcheckmake -C src/test installcheck-cbdb-parallelImpact
EXPLAINoutputs the maximum value across workers.Checklist
Additional Context
CI Skip Instructions