PHOENIX-7891 Explain the query optimizer's index selection rationale - #2513
Merged
Conversation
Capture the query optimizer's index selection rationale with a new data model and a closed set of RULE_* and REASON_* string constants plumbed through QueryPlan/BaseQueryPlan/DelegateQueryPlan. AddPlanResult returns from the two addPlan overloads, and a DecisionState accumulator is threaded through. A new helper method assigns the winning rule and collected rejections. New ExplainPlanAttributes fields indexRule and indexRejected are set in BaseQueryPlan from getOptimizerDecision(), with matching ExplainPlanTestUtil fluent assertions indexRule, indexRuleStartsWith, indexRejectedCount, indexRejected, indexRejectedNone. EXPLAIN output gains 'INDEX <name> [<kind>] [/* <rule> */]' for chosen index and one '/* !INDEX <name> -- <reason> */' line per rejected index. Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a structured “optimizer decision” model to capture why the query optimizer chose a particular index (or the data table), and wires that rationale through QueryPlan into both structured explain attributes and EXPLAIN text output.
Changes:
- Introduces
OptimizerDecision,OptimizerReasons(RULE_*/REASON_*), andRejectedIndexEntry, and records these during plan selection inQueryOptimizer. - Extends explain plumbing so
EXPLAINcan render the chosen rule as a comment on theINDEXline and render/* !INDEX ... -- reason */lines for rejected candidates; also exposesindexRule/indexRejectedviaExplainPlanAttributes. - Updates unit and integration tests to assert optimizer rule/rejection metadata and updated
EXPLAINoutput formatting.
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| phoenix-core/src/test/java/org/apache/phoenix/query/QueryPlanTest.java | Updates plan assertions to include indexRule / rejected-index expectations. |
| phoenix-core/src/test/java/org/apache/phoenix/query/explain/ExplainPlanTestUtil.java | Adds fluent assertions for indexRule and rejected-index lists. |
| phoenix-core/src/test/java/org/apache/phoenix/query/explain/ExplainPlanTest.java | Updates expected EXPLAIN text/JSON and adds helper assertions for new INDEX comments and !INDEX lines. |
| phoenix-core/src/test/java/org/apache/phoenix/compile/TenantSpecificViewIndexCompileTest.java | Adds optimizer rule/rejection assertions to compile-time plan tests. |
| phoenix-core/src/test/java/org/apache/phoenix/compile/StatementHintsCompilationTest.java | Adds optimizer rule/rejection assertions for hint-related compilation paths. |
| phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java | Asserts chosen rule and rejected index reason in optimizer selection tests. |
| phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java | Adds optimizer decision assertions to regression tests. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificViewIndexIT.java | Adds optimizer decision assertions to end-to-end view/index scenarios. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/ReverseScanIT.java | Adds optimizer decision assertions to reverse scan scenarios. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/json/JsonFunctionsIT.java | Adds optimizer decision assertions for JSON/index-related plans. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/join/HashJoinLocalIndexIT.java | Adds optimizer decision assertions for join subplans and rejection reasons. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/join/HashJoinGlobalIndexIT.java | Adds optimizer decision assertions for join subplans and rejection reasons. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/InListIT.java | Adds optimizer decision assertions for point-lookup and range-scan IN-list plans. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java | Adds optimizer decision assertions to view-index usage tests. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SingleCellIndexIT.java | Asserts rule and explicit rejection reasons (e.g., NO_INDEX hint). |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SaltedIndexIT.java | Adds optimizer decision assertions across salted index/table variants. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/PartialIndexIT.java | Adds optimizer rule assertions for partial index + hint behavior. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java | Adds optimizer decision assertions to mutable index selection tests. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java | Adds optimizer decision assertions and explicit local-vs-global rejection reasons. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexUsageIT.java | Adds optimizer rule/rejection assertions across several index-usage patterns. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexOptimizationIT.java | Adds optimizer rule/rejection assertions for optimization flows and subplans. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexCheckerIT.java | Adds overload to assert expected rule and asserts rule/rejections in checks. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ChildViewsUseParentViewIndexIT.java | Adds optimizer rule assertions for child-view index selection. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/CostBasedDecisionIT.java | Adds optimizer rule/rejection assertions for cost-based winner/loser decisions. |
| phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java | Adds optimizer rule assertions to shared base IT helpers. |
| phoenix-core-client/src/main/java/org/apache/phoenix/optimize/RejectedIndexEntry.java | New value type for a rejected index + reason. |
| phoenix-core-client/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java | Records optimizer decisions, threads DecisionState, and tags rejection reasons. |
| phoenix-core-client/src/main/java/org/apache/phoenix/optimize/OptimizerReasons.java | New closed-set string vocabulary for rules and rejection reasons. |
| phoenix-core-client/src/main/java/org/apache/phoenix/optimize/OptimizerDecision.java | New model capturing chosen index, rule, and rejected index entries. |
| phoenix-core-client/src/main/java/org/apache/phoenix/iterate/ExplainTable.java | Renders rule comments on INDEX and prints !INDEX rejection lines. |
| phoenix-core-client/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java | Exposes optimizer decision to explain rendering. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/DelegateQueryPlan.java | Delegates optimizer decision get/set to wrapped plan. |
| phoenix-core-client/src/main/java/org/apache/phoenix/execute/BaseQueryPlan.java | Stores optimizer decision and propagates it into structured explain attributes. |
| phoenix-core-client/src/main/java/org/apache/phoenix/compile/QueryPlan.java | Adds default get/set methods for optimizer decisions. |
| phoenix-core-client/src/main/java/org/apache/phoenix/compile/ExplainPlanAttributes.java | Adds indexRule and indexRejected fields + builder plumbing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Contributor
Author
Test Results
Unit tests
Integration testsIndex suites
Join suites
Cost / optimizer
View / tenant suites
Other EXPLAIN-asserting suites
Pre-existing failures (not introduced by this change)
|
apurtell
added a commit
to apurtell/phoenix
that referenced
this pull request
Jun 17, 2026
…pache#2513) Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
asf-gitbox-commits
pushed a commit
that referenced
this pull request
Jul 24, 2026
…2513) Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
apurtell
added a commit
to apurtell/phoenix
that referenced
this pull request
Aug 4, 2026
…pache#2513) 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 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.
Capture the query optimizer's index selection rationale with a new data model and a closed set of
RULE_*andREASON_*string constants plumbed throughQueryPlan/BaseQueryPlan/DelegateQueryPlan.AddPlanResultreturns from the twoaddPlanoverloads, and aDecisionStateaccumulator is threaded through. A new helper method assigns the winning rule and collected rejections. NewExplainPlanAttributesfieldsindexRuleandindexRejectedare set inBaseQueryPlanfromgetOptimizerDecision(), with matchingExplainPlanTestUtilfluent assertionsindexRule,indexRuleStartsWith,indexRejectedCount,indexRejected, andindexRejectedNone.EXPLAINoutput gainsINDEX <name> [<kind>] [/* <rule> */]for chosen index and one/* !INDEX <name> -- <reason> */line per rejected index.Co-authored-by: Claude Opus 4.8[1m] noreply@anthropic.com