Skip to content

PHOENIX-7890 Improve EXPLAIN for joins and unions - #2510

Merged
apurtell merged 3 commits into
apache:PHOENIX-7876-featurefrom
apurtell:PHOENIX-7890
Jun 10, 2026
Merged

PHOENIX-7890 Improve EXPLAIN for joins and unions#2510
apurtell merged 3 commits into
apache:PHOENIX-7876-featurefrom
apurtell:PHOENIX-7890

Conversation

@apurtell

Copy link
Copy Markdown
Contributor

The chosen JoinCompiler.Strategy and the SKIP MERGE and DELAYED EVALUATION decorators move out of inline parentheticals into a single trailing SQL comment per join operator line. HashJoinPlan and SortMergeJoinPlan gain a JoinCompiler.Strategy strategy field and getter/setter. QueryCompiler.compileJoinQuery threads the chosen strategy through HashJoinPlan.create(...).

UnionPlan.getExplainPlan() is rewritten to compose recursively from each branch's getExplainPlan() (like SortMergeJoinPlan.getExplainPlan()). The N branches are represented via the existing subPlans list. A new UnionResultIterators.explainBranches(plans, planSteps, builder) helper is the single source of truth for branch composition. The two ResultIterators.explain(...) SPI overrides on UnionResultIterators become thin delegates to it. UnionPlan.getExplainPlan() no longer triggers sub-plan execution, so connectionless tests can check them.

Minor housekeeping: Replace string 'Truncate Table' with 'TRUNCATE TABLE' in EXPLAIN DDL.

Add TPC-DS derived ITs asserting the full ordered results of various UNION and JOIN plans and expected assertPlan assertions.

Add a TPC-DS-like IT suite that exercises the PHOENIX-7890 EXPLAIN
improvements for joins and unions. Twenty adapted queries (14 single
channel, 6 cross channel) run over a deterministic fixture, parameterized
across NO_INDEX and GLOBAL_INDEX schemas. Each test asserts the full
ordered result plus the EXPLAIN operator markers (hash build, union all,
sort-merge join) in both parameters, and verifies covering-index usage
in the GLOBAL_INDEX parameter where the optimizer rewrites onto SS_I,
INV_I, or CS_I.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors EXPLAIN output for JOIN and UNION plans to make join strategy/decorators clearer and to make UNION explain composition recursive (without executing sub-plans), and updates/extends tests accordingly.

Changes:

  • Move join strategy + decorators (e.g., SKIP MERGE, DELAYED EVALUATION) into a single trailing SQL comment per join-operator line, and thread join strategy into HashJoinPlan / SortMergeJoinPlan.
  • Rewrite UnionPlan.getExplainPlan() to recursively compose branch explain plans via a shared UnionResultIterators.explainBranches(...) helper (avoiding sub-plan execution during explain).
  • Add TPC-DS-derived deterministic fixtures + integration tests asserting ordered results and expected plan fragments for UNION/JOIN queries; update existing plan-assert tests for the new explain format.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
phoenix-core/src/test/java/org/apache/phoenix/query/explain/ExplainPlanTest.javaUpdates expected EXPLAIN strings and adds UNION-of-joins coverage aligned with new recursive composition.
phoenix-core/src/test/java/org/apache/phoenix/end2end/tpcds/TPCDSLikeExpectedRegenerator.javaAdds a developer utility to regenerate embedded expected result arrays for the new TPC-DS-like ITs.
phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.javaUpdates join explain assertions to include the new trailing strategy comment.
phoenix-core/src/it/java/org/apache/phoenix/end2end/UnionAllIT.javaUpdates UNION EXPLAIN attribute assertions to validate subPlans branch structure.
phoenix-core/src/it/java/org/apache/phoenix/end2end/tpcds/TPCDSLikeSingleChannelIT.javaAdds single-channel TPC-DS-derived ITs asserting full ordered results + plan markers.
phoenix-core/src/it/java/org/apache/phoenix/end2end/tpcds/TPCDSLikeFixture.javaAdds deterministic fixture schema/data generation for the new TPC-DS-like IT suite.
phoenix-core/src/it/java/org/apache/phoenix/end2end/tpcds/TPCDSLikeCrossChannelIT.javaAdds cross-channel UNION/SORT-MERGE focused ITs with result + plan assertions.
phoenix-core/src/it/java/org/apache/phoenix/end2end/tpcds/TPCDSLikeBaseIT.javaAdds shared parameterization/plumbing for the TPC-DS-like ITs (base vs indexed schema).
phoenix-core/src/it/java/org/apache/phoenix/end2end/tpcds/TPCDSLikeAssertions.javaAdds helpers to assert full ordered results and plan fragments; supports regeneration mode.
phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryWithTableSampleIT.javaUpdates UNION and JOIN explain assertions to the new subPlans/comment format.
phoenix-core/src/it/java/org/apache/phoenix/end2end/join/HashJoinNoIndexIT.javaUpdates join plan assertions to include trailing strategy comment.
phoenix-core/src/it/java/org/apache/phoenix/end2end/join/HashJoinMoreIT.javaUpdates join plan assertions (incl. SKIP MERGE) to the new trailing comment format.
phoenix-core/src/it/java/org/apache/phoenix/end2end/join/HashJoinLocalIndexIT.javaUpdates join plan assertions to include trailing strategy comment.
phoenix-core/src/it/java/org/apache/phoenix/end2end/join/HashJoinGlobalIndexIT.javaUpdates join plan assertions to include trailing strategy comment.
phoenix-core/src/it/java/org/apache/phoenix/end2end/index/IndexUsageIT.javaUpdates join explain assertion to the new trailing comment format.
phoenix-core/src/it/java/org/apache/phoenix/end2end/index/GlobalIndexOptimizationIT.javaUpdates SKIP-SCAN-JOIN explain assertion to include trailing strategy comment.
phoenix-core/src/it/java/org/apache/phoenix/end2end/CostBasedDecisionIT.javaUpdates UNION/JOIN explain assertions to use subPlans instead of lhs/rhs chaining.
phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.javaNormalizes TRUNCATE explain text to TRUNCATE TABLE.
phoenix-core-client/src/main/java/org/apache/phoenix/iterate/UnionResultIterators.javaIntroduces explainBranches(...) helper and delegates explain methods to it.
phoenix-core-client/src/main/java/org/apache/phoenix/execute/UnionPlan.javaRewrites union explain composition to be branch-recursive and non-executing; appends tail steps explicitly.
phoenix-core-client/src/main/java/org/apache/phoenix/execute/SortMergeJoinPlan.javaAdds strategy field and updates sort-merge join header to include /* SORT_MERGE */.
phoenix-core-client/src/main/java/org/apache/phoenix/execute/HashJoinPlan.javaAdds strategy field, updates join headers to trailing comment format, and threads strategy through create().
phoenix-core-client/src/main/java/org/apache/phoenix/compile/QueryCompiler.javaThreads join strategy into HashJoinPlan.create(...) calls and updates subquery wrapping call sites.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@apurtell

Copy link
Copy Markdown
ContributorAuthor

Test Results

Unit tests (connectionless)

TestRunFailuresErrorsSkippedResult
org.apache.phoenix.query.explain.ExplainPlanTest63000PASS
org.apache.phoenix.compile.QueryCompilerTest215002PASS

ExplainPlanTest includes the new testUnionAllOfHashJoins case covering the deeply nested
union-of-hash-joins explain output (union root → branch scan → hash-join sub-plan), plus the
updated testHashJoinInner, testHashJoinSemiInSubquery, testSortMergeJoin, and testUnionAll.

Integration tests

TestRunFailuresErrorsSkippedResult
org.apache.phoenix.end2end.join.HashJoinNoIndexIT33000PASS
org.apache.phoenix.end2end.join.HashJoinGlobalIndexIT33000PASS
org.apache.phoenix.end2end.join.HashJoinLocalIndexIT34000PASS
org.apache.phoenix.end2end.join.HashJoinMoreIT10000PASS
org.apache.phoenix.end2end.index.IndexUsageIT39000PASS
org.apache.phoenix.end2end.index.GlobalIndexOptimizationIT7000PASS
org.apache.phoenix.end2end.QueryWithTableSampleIT12000PASS
org.apache.phoenix.end2end.UnionAllIT19000PASS
org.apache.phoenix.end2end.CostBasedDecisionIT20000PASS
org.apache.phoenix.end2end.join.SortMergeJoinNoIndexIT35000PASS
org.apache.phoenix.end2end.join.SortMergeJoinGlobalIndexIT35000PASS
org.apache.phoenix.end2end.join.SortMergeJoinLocalIndexIT35000PASS
org.apache.phoenix.end2end.SortMergeJoinMoreIT10000PASS
org.apache.phoenix.end2end.join.SubqueryUsingSortMergeJoinIT21000PASS
org.apache.phoenix.end2end.tpcds.TPCDSLikeSingleChannelIT28000PASS
org.apache.phoenix.end2end.tpcds.TPCDSLikeCrossChannelIT12000PASS

The two TPCDSLike*IT classes are new TPC-DS derived ITs that exercise joins and unions. Each query runs over a deterministic fixture and is parameterized across NO_INDEX and GLOBAL_INDEX schemas. Every case asserts the full ordered result plus the EXPLAIN operator markers (HASH BUILD, UNION ALL OVER N QUERIES, SORT-MERGE-JOIN (INNER/FULL)) in both parameters, and additionally verifies covering-index usage (SS_I, INV_I, CS_I) in the GLOBAL_INDEX parameter where the optimizer rewrites the fact-table scan onto a global index.

Totals

  • Unit tests: 278 run, 0 failures, 0 errors (2 skipped).
  • Integration tests: 383 run, 0 failures, 0 errors, 0 skipped.
  • Overall: 661 run, 0 failures, 0 errors.

@apurtell
apurtell merged commit 820f799 into apache:PHOENIX-7876-featureJun 10, 2026
@apurtell
apurtell deleted the PHOENIX-7890 branch June 10, 2026 05:26
asf-gitbox-commits pushed a commit that referenced this pull request Jun 10, 2026
Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
apurtell added a commit to apurtell/phoenix that referenced this pull request Jun 17, 2026
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
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
Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@apurtell