Uh oh!
There was an error while loading. Please reload this page.
PHOENIX-7899 Emit plan level estimates only once in EXPLAIN - #2520
Merged
Conversation
Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adjusts Phoenix’s EXPLAIN output so the plan-total estimate columns (EST_BYTES_READ, EST_ROWS_READ, EST_INFO_TS) are emitted only once at the top of the result set (instead of being repeated on every plan-step row), and threads these plan-total values through ExplainPlanAttributes while preserving per-scan estimates separately.
Changes:
- Emit plan-total estimate cells only on the first
EXPLAINrow; subsequent rows return SQLNULLfor those estimate columns. - Extend
ExplainPlanAttributesto carry plan-total estimates (estimatedRows,estimatedSizeInBytes,estimateInfoTs) and add explicit per-scan fields (scanEstimatedRows,scanEstimatedSizeInBytes). - Update/extend unit and integration tests to validate first-row-only estimate cells and the new attributes/JSON normalization behavior.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| phoenix-core/src/test/java/org/apache/phoenix/query/explain/ExplainPlanTestUtil.java | Adds assertions for new scan-level estimate fields and estimate info timestamp. |
| phoenix-core/src/test/java/org/apache/phoenix/query/explain/ExplainPlanTest.java | Updates JSON normalizer tests and default attribute set to include new fields. |
| phoenix-core/src/test/java/org/apache/phoenix/query/explain/ExplainJsonNormalizer.java | Nulls additional estimate-related fields during normalization. |
| phoenix-core/src/it/java/org/apache/phoenix/schema/stats/BaseStatsCollectorIT.java | Migrates plan assertions to scan-level estimate accessors. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/ExplainPlanWithStatsEnabledIT.java | Adds IT coverage ensuring estimates match stats and appear only on the first EXPLAIN row. |
| phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java | Changes EXPLAIN materialization to emit estimate cells only for the first row. |
| phoenix-core-client/src/main/java/org/apache/phoenix/iterate/ExplainTable.java | Adds helper to populate plan-total estimate attributes for root plans. |
| phoenix-core-client/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java | Switches builder population to the new scan-level estimate fields. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/UnionPlan.java | Populates root plan estimate attributes for union plans. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/SortMergeJoinPlan.java | Populates root plan estimate attributes for sort-merge join plans. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java | Populates root plan estimate attributes for hash join plans. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/ClientScanPlan.java | Populates root plan estimate attributes for client scan plans. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/ClientAggregatePlan.java | Populates root plan estimate attributes for client aggregate plans. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/BaseQueryPlan.java | Ensures root plans include plan-total estimate attributes in V2 explain attributes. |
| phoenix-core-client/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java | Ensures UPSERT explain attributes include root plan estimate attributes. |
| phoenix-core-client/src/main/java/org/apache/phoenix/compile/ExplainPlanAttributes.java | Adds plan-total estimate fields + scan-level estimate fields and builder support. |
| phoenix-core-client/src/main/java/org/apache/phoenix/compile/DeleteCompiler.java | Ensures DELETE explain attributes include root plan estimate attributes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.
apurtell
commented
Jun 11, 2026
ContributorAuthor
Test results
|
asf-gitbox-commits pushed a commit
that referenced
this pull request
Jul 24, 2026
Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
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 freeto 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.
The three effectively plan level estimate columns become part of the top-of-plan disclosure.
Today
PhoenixStatement.ExecutableExplainStatement.compilePlanemits the sameEST_BYTES_READ/EST_ROWS_READ/EST_INFO_TScells on everyplanStepsrow, so a reader scanning the result set sees them repeated on every operator and reasonably assumes they are per-step.The three
PhoenixKeyValueUtil.newKeyValue(...)calls forEXPLAIN_PLAN_BYTES_ESTIMATE,EXPLAIN_PLAN_ROWS_ESTIMATE, andEXPLAIN_PLAN_ESTIMATE_INFO_TSare hoisted. Subsequent rows carry just theEXPLAIN_PLAN_COLUMNcell and the missing estimate cells surface as SQLNULL. TheRowProjectoris unchanged, and the whole block is skipped whengetEstimated*ToScan()returns null. The three plan-total fields are added toExplainPlanAttributes.Co-authored-by: Claude Opus 4.8[1m] noreply@anthropic.com