Skip to content

planner: tidb_opt_ordering_index_selectivity_ratio for merge join (#67588)#67906

Open
ti-chi-bot wants to merge 1 commit intopingcap:release-8.5from
ti-chi-bot:cherry-pick-67588-to-release-8.5
Open

planner: tidb_opt_ordering_index_selectivity_ratio for merge join (#67588)#67906
ti-chi-bot wants to merge 1 commit intopingcap:release-8.5from
ti-chi-bot:cherry-pick-67588-to-release-8.5

Conversation

@ti-chi-bot
Copy link
Copy Markdown
Member

@ti-chi-bot ti-chi-bot commented Apr 20, 2026

This is an automated cherry-pick of #67588

What problem does this PR solve?

Issue Number: ref #62034 , close #67595

Problem Summary:

What changed and how does it work?

Extends the tidb_opt_ordering_index_selectivity_ratio (“ordering penalty”) modeling to MergeJoin by reusing a shared child-ExpectedCnt calculation, and adds a planner/cardinality test intended to validate the new cost behavior.

Changes:

Introduce physicalop.CalcChildExpectedCnt to centralize ordered-join child ExpectedCnt scaling + ordering penalty logic.

  • Apply the centralized logic to MergeJoin (and refactor existing IndexJoin/Apply usage to call the shared helper).
  • Add a unit test for MergeJoin cost sensitivity to tidb_opt_ordering_index_selectivity_ratio.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Please refer to Release Notes Language Style Guide to write a quality release note.

None

Summary by CodeRabbit

  • New Features

    • Extended query optimizer to evaluate additional join execution strategies and improve cost-based plan selection across complex scenarios.
  • Tests

    • Added comprehensive test cases for optimizer configuration parameters and their impact on query execution plans.

Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
@ti-chi-bot ti-chi-bot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/L Denotes a PR that changes 100-499 lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR. labels Apr 20, 2026
@ti-chi-bot
Copy link
Copy Markdown
Member Author

@terry1purcell This PR has conflicts, I have hold it.
Please resolve them or ask others to resolve them, then comment /unhold to remove the hold label.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Apr 20, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign wddevries for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Apr 20, 2026

This cherry pick PR is for a release branch and has not yet been approved by triage owners.
Adding the do-not-merge/cherry-pick-not-approved label.

To merge this cherry pick:

  1. It must be LGTMed and approved by the reviewers firstly.
  2. For pull requests to TiDB-x branches, it must have no failed tests.
  3. AFTER it has lgtm and approved labels, please wait for the cherry-pick merging approval from triage owners.
Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Apr 20, 2026

@ti-chi-bot: ## If you want to know how to resolve it, please read the guide in TiDB Dev Guide.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository.

@ti-chi-bot ti-chi-bot bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Apr 20, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

This PR introduces merge join physical operator planning with cost estimation, refactors index join construction into static enumeration and completion phases, adds ordering-aware child row count estimation for Apply operations, and provides supporting utility functions for physical plan manipulation and selectivity ratio handling.

Changes

Cohort / File(s) Summary
Physical Merge Join Implementation
pkg/planner/core/operator/physicalop/physical_merge_join.go
Adds complete PhysicalMergeJoin operator with plan enumeration (GetMergeJoin), cost computation (both v1 and v2), collation validation, null-equality handling, and lifecycle hooks (Init, Clone, ResolveIndices). Includes helpers for join-key prefix matching against sort properties and enforced merge join generation when explicitly preferred.
Physical Plan Utilities
pkg/planner/core/operator/physicalop/physical_utils.go
New utility module providing plan transformation (ClonePhysicalPlan, FlattenListPushDownPlan), statistics extraction (GetTblStats, GetDynamicAccessPartition), virtual column resolution, unique index key encoding, and CalcChildExpectedCnt for modeling extra scanned rows based on OptOrderingIdxSelRatio when ordering is required.
Index Join Refactoring & Apply Updates
pkg/planner/core/exhaust_physical_plans.go
Refactors index join enumeration into constructIndexJoinStatic (enumerate plans before inner side built) and completePhysicalIndexJoin (fill deferred runtime fields after inner task built). Updates exhaustPhysicalPlans4LogicalApply to use CalcChildExpectedCnt for ordering-aware outerExpectedCnt calculation when parent requires order properties.
Test Data & Selectivity Tests
pkg/bindinfo/testdata/binding_auto_suite_out.json, pkg/planner/cardinality/selectivity_test.go
Adds JSON testdata with expected optimizer outputs for TestPlanGeneration and TestRelevantOptVarsAndFixes suites. Introduces TestOrderingIdxSelectivityRatioForMergeJoin and TestOrderingIdxSelectivityRatioForApply test cases validating cost monotonicity across ratio values -1, 0, 0.5, 1; contains unresolved merge-conflict markers.
Build Configuration
pkg/planner/cardinality/BUILD.bazel
Changes cardinality_test shard count from 34 to 48; file contains visible merge-conflict markers (<<<<<<< HEAD, =======, >>>>>>>) around shard_count assignment indicating unresolved merge state.

Sequence Diagram(s)

sequenceDiagram
    participant Planner
    participant MergeJoinPlan as MergeJoin<br/>Planning
    participant IndexJoinPlan as IndexJoin<br/>Planning
    participant CostCalc as Cost<br/>Calculator
    participant SelectivityRatio as Selectivity<br/>Ratio Handler

    Planner->>MergeJoinPlan: Enumerate join candidates<br/>(left/right keys, sort props)
    MergeJoinPlan->>MergeJoinPlan: Validate collation &<br/>match sort properties
    MergeJoinPlan->>CostCalc: Request cost (v1/v2)
    CostCalc->>SelectivityRatio: GetOptOrderingIdxSelRatio
    SelectivityRatio-->>CostCalc: ratio value
    CostCalc-->>MergeJoinPlan: cost estimate

    Planner->>IndexJoinPlan: constructIndexJoinStatic<br/>(before inner built)
    IndexJoinPlan->>IndexJoinPlan: Push IndexJoinRuntimeProp<br/>to inner child
    Planner->>IndexJoinPlan: Inner task complete
    IndexJoinPlan->>IndexJoinPlan: completePhysicalIndexJoin<br/>(fill runtime fields)
    IndexJoinPlan->>CostCalc: Request cost
    CostCalc-->>IndexJoinPlan: cost estimate

    MergeJoinPlan->>Planner: Compare costs
    IndexJoinPlan->>Planner: Compare costs
    Planner->>Planner: Select operator<br/>with lower cost
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • PR #67588: Directly related—modifies same planner areas with CalcChildExpectedCnt, MergeJoin planning additions, and selectivity ratio test coverage.
  • PR #66156: Modifies exhaust_physical_plans.go to refactor index-join enumeration and physical plan construction phases.
  • PR #66786: Updates Apply outer-expected-count calculation (calcOuterExpectedCnt) and selectivity behavior with test additions aligned to this PR's changes.

Suggested labels

cherry-pick-approved

Suggested reviewers

  • guo-shaoge
  • qw4990
  • AilinKid

Poem

🐰 A merge joins with grace,
Index plans find their place,
Selectivity guides the way—
Optimized costs save the day!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 67.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: extending tidb_opt_ordering_index_selectivity_ratio support to MergeJoin, which aligns with the PR's primary objective.
Description check ✅ Passed The description includes the required template structure, issue numbers, problem summary, changes explanation, and test checklist completion; however, no linked issues check exists in the provided context.
Linked Issues check ✅ Passed The code changes (physicalop.CalcChildExpectedCnt helper, MergeJoin cost modeling updates, and unit tests) directly address the root cause identified in #67595: cost under-estimation of IndexFullScan under LIMIT by applying tidb_opt_ordering_index_selectivity_ratio scaling.
Out of Scope Changes check ✅ Passed All changes directly support the objectives: physicalop.CalcChildExpectedCnt centralizes the ordering penalty logic for MergeJoin/IndexJoin/Apply, new test validates MergeJoin cost sensitivity, testdata captures expected plan structures, and Bazel shard adjustment maintains test infrastructure—no out-of-scope modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@tiprow
Copy link
Copy Markdown

tiprow bot commented Apr 20, 2026

@ti-chi-bot: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
fast_test_tiprow_for_release c771e9c link true /test fast_test_tiprow_for_release

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Apr 20, 2026

@ti-chi-bot: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
idc-jenkins-ci-tidb/check_dev c771e9c link true /test check-dev
idc-jenkins-ci-tidb/mysql-test c771e9c link true /test mysql-test
idc-jenkins-ci-tidb/check_dev_2 c771e9c link true /test check-dev2
idc-jenkins-ci-tidb/unit-test c771e9c link true /test unit-test
idc-jenkins-ci-tidb/build c771e9c link true /test build

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/planner/core/exhaust_physical_plans.go (1)

2587-2605: ⚠️ Potential issue | 🔴 Critical

Resolve the merge conflict and fix three critical issues in Apply planning with ordering support.

The file contains unresolved merge conflict markers (lines 2584–2597) that prevent compilation. Beyond that, the incoming branch has two bugs:

  1. Undefined variable stats0 (line 2591): This variable does not exist in the exhaustPhysicalPlans4LogicalApply function scope. Use la.Children()[0].StatsInfo().RowCount instead to access the outer child's stats.

  2. Unused outerExpectedCnt: The computed ordering-aware count is not wired into Apply's properties. Line 2596 still passes hardcoded math.MaxFloat64 for the outer child's expected count, ignoring the computed value.

The proposed fix correctly:

  • Replaces undefined stats0 with the outer child's stats via la.Children()[0].StatsInfo().RowCount
  • Wires outerExpectedCnt into the outer property's ExpectedCnt field so ordering-based selectivity ratio actually influences planning
Proposed fix
 	outerExpectedCnt := math.MaxFloat64
 	if !prop.IsSortItemEmpty() {
-		outerExpectedCnt = physicalop.CalcChildExpectedCnt(la.SCtx(), prop, stats0.RowCount, la.StatsInfo().RowCount)
+		outerExpectedCnt = physicalop.CalcChildExpectedCnt(
+			la.SCtx(), prop, la.Children()[0].StatsInfo().RowCount, la.StatsInfo().RowCount,
+		)
 	}
 
 	apply := physicalop.PhysicalApply{
 		PhysicalHashJoin: *join,
 		OuterSchema:      la.CorCols,
@@
 		la.StatsInfo().ScaleByExpectCnt(prop.ExpectedCnt),
 		la.QueryBlockOffset(),
-		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64, SortItems: prop.SortItems, CTEProducerStatus: prop.CTEProducerStatus},
+		&property.PhysicalProperty{ExpectedCnt: outerExpectedCnt, SortItems: prop.SortItems, CTEProducerStatus: prop.CTEProducerStatus},
 		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64, CTEProducerStatus: prop.CTEProducerStatus})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/planner/core/exhaust_physical_plans.go` around lines 2587 - 2605, The
merge left conflict markers in exhaustPhysicalPlans4LogicalApply and the
ordering-aware outer row estimate isn't applied: replace the undefined stats0
with la.Children()[0].StatsInfo().RowCount when computing outerExpectedCnt,
remove the conflict markers, and then pass outerExpectedCnt into the
PhysicalApply.Init call by setting the outer property's ExpectedCnt to
outerExpectedCnt (instead of math.MaxFloat64) so the computed ordering-aware
selectivity is used; ensure the rest of the PhysicalApply.Init arguments (inner
property ExpectedCnt) remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/planner/cardinality/selectivity_test.go`:
- Around line 1421-1426: Replace the incorrect usage of ast.NewCIStr with the
existing pmodel.NewCIStr in the TableByName calls so the code compiles and
matches the rest of the file; specifically update the two calls around
InfoSchema() where TableByName(context.Background(), ast.NewCIStr("test"),
ast.NewCIStr("t1")) and TableByName(..., ast.NewCIStr("t2")) are used to instead
call TableByName(context.Background(), pmodel.NewCIStr("test"),
pmodel.NewCIStr("t1")) and pmodel.NewCIStr("t2"), keeping the surrounding
variables tb1/tb2, err, tbl1 and require.NoError checks unchanged.

In `@pkg/planner/core/exhaust_physical_plans.go`:
- Around line 739-750: The static enumeration path currently ignores null-safe
equality flags (isNullEQ) from p.GetJoinKeys(), allowing joins using `<=>` to be
considered for IndexJoin; update the enumeration to mirror constructIndexJoin by
checking the isNullEQ slice (e.g., any true entry) after calling GetJoinKeys
(with outerIdx logic) and skip/reject building IndexJoin candidates when a
null-safe equality is present so IndexJoin is not admitted for `<=>` semantics.

---

Outside diff comments:
In `@pkg/planner/core/exhaust_physical_plans.go`:
- Around line 2587-2605: The merge left conflict markers in
exhaustPhysicalPlans4LogicalApply and the ordering-aware outer row estimate
isn't applied: replace the undefined stats0 with
la.Children()[0].StatsInfo().RowCount when computing outerExpectedCnt, remove
the conflict markers, and then pass outerExpectedCnt into the PhysicalApply.Init
call by setting the outer property's ExpectedCnt to outerExpectedCnt (instead of
math.MaxFloat64) so the computed ordering-aware selectivity is used; ensure the
rest of the PhysicalApply.Init arguments (inner property ExpectedCnt) remain
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f6a4faea-719d-4351-ba85-abfdcb94b2be

📥 Commits

Reviewing files that changed from the base of the PR and between ae18096 and c771e9c.

📒 Files selected for processing (6)
  • pkg/bindinfo/testdata/binding_auto_suite_out.json
  • pkg/planner/cardinality/BUILD.bazel
  • pkg/planner/cardinality/selectivity_test.go
  • pkg/planner/core/exhaust_physical_plans.go
  • pkg/planner/core/operator/physicalop/physical_merge_join.go
  • pkg/planner/core/operator/physicalop/physical_utils.go

Comment on lines +1421 to +1426
is := dom.InfoSchema()
tb1, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t1"))
require.NoError(t, err)
tbl1 := tb1.Meta()
tb2, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t2"))
require.NoError(t, err)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C2 '\bast\.NewCIStr\b|\bpmodel\.NewCIStr\b' pkg/planner/cardinality/selectivity_test.go

Repository: pingcap/tidb

Length of output: 4559


Replace ast.NewCIStr with pmodel.NewCIStr for consistency and to fix compile error.

Lines 1422 and 1425 use ast.NewCIStr, which is not imported in this file. Every other TableByName call in the file uses the existing pmodel.NewCIStr alias. These lines will fail to compile as written.

Proposed fix
-	tb1, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t1"))
+	tb1, err := is.TableByName(context.Background(), pmodel.NewCIStr("test"), pmodel.NewCIStr("t1"))
 	require.NoError(t, err)
 	tbl1 := tb1.Meta()
-	tb2, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t2"))
+	tb2, err := is.TableByName(context.Background(), pmodel.NewCIStr("test"), pmodel.NewCIStr("t2"))
 	require.NoError(t, err)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
is := dom.InfoSchema()
tb1, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t1"))
require.NoError(t, err)
tbl1 := tb1.Meta()
tb2, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t2"))
require.NoError(t, err)
is := dom.InfoSchema()
tb1, err := is.TableByName(context.Background(), pmodel.NewCIStr("test"), pmodel.NewCIStr("t1"))
require.NoError(t, err)
tbl1 := tb1.Meta()
tb2, err := is.TableByName(context.Background(), pmodel.NewCIStr("test"), pmodel.NewCIStr("t2"))
require.NoError(t, err)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/planner/cardinality/selectivity_test.go` around lines 1421 - 1426,
Replace the incorrect usage of ast.NewCIStr with the existing pmodel.NewCIStr in
the TableByName calls so the code compiles and matches the rest of the file;
specifically update the two calls around InfoSchema() where
TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t1")) and
TableByName(..., ast.NewCIStr("t2")) are used to instead call
TableByName(context.Background(), pmodel.NewCIStr("test"),
pmodel.NewCIStr("t1")) and pmodel.NewCIStr("t2"), keeping the surrounding
variables tb1/tb2, err, tbl1 and require.NoError checks unchanged.

Comment on lines +739 to +750
joinType := p.JoinType
var (
innerJoinKeys []*expression.Column
outerJoinKeys []*expression.Column
isNullEQ []bool
)
if outerIdx == 0 {
outerJoinKeys, innerJoinKeys, isNullEQ, _ = p.GetJoinKeys()
} else {
innerJoinKeys, outerJoinKeys, isNullEQ, _ = p.GetJoinKeys()
}
chReqProps := make([]*property.PhysicalProperty, 2)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Preserve the null-safe equality rejection in the static index-join path.

constructIndexJoin rejects hasNullEQ because IndexJoin does not support null-safe join keys. The static enumeration path should keep the same guard; otherwise <=> joins can be admitted and later completed as IndexJoin candidates with incorrect NULL semantics.

🐛 Proposed fix
 	var (
 		innerJoinKeys []*expression.Column
 		outerJoinKeys []*expression.Column
 		isNullEQ      []bool
+		hasNullEQ     bool
 	)
 	if outerIdx == 0 {
-		outerJoinKeys, innerJoinKeys, isNullEQ, _ = p.GetJoinKeys()
+		outerJoinKeys, innerJoinKeys, isNullEQ, hasNullEQ = p.GetJoinKeys()
 	} else {
-		innerJoinKeys, outerJoinKeys, isNullEQ, _ = p.GetJoinKeys()
+		innerJoinKeys, outerJoinKeys, isNullEQ, hasNullEQ = p.GetJoinKeys()
 	}
+	// TODO: support null equal join keys for index join.
+	if hasNullEQ {
+		return nil
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
joinType := p.JoinType
var (
innerJoinKeys []*expression.Column
outerJoinKeys []*expression.Column
isNullEQ []bool
)
if outerIdx == 0 {
outerJoinKeys, innerJoinKeys, isNullEQ, _ = p.GetJoinKeys()
} else {
innerJoinKeys, outerJoinKeys, isNullEQ, _ = p.GetJoinKeys()
}
chReqProps := make([]*property.PhysicalProperty, 2)
joinType := p.JoinType
var (
innerJoinKeys []*expression.Column
outerJoinKeys []*expression.Column
isNullEQ []bool
hasNullEQ bool
)
if outerIdx == 0 {
outerJoinKeys, innerJoinKeys, isNullEQ, hasNullEQ = p.GetJoinKeys()
} else {
innerJoinKeys, outerJoinKeys, isNullEQ, hasNullEQ = p.GetJoinKeys()
}
// TODO: support null equal join keys for index join.
if hasNullEQ {
return nil
}
chReqProps := make([]*property.PhysicalProperty, 2)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/planner/core/exhaust_physical_plans.go` around lines 739 - 750, The
static enumeration path currently ignores null-safe equality flags (isNullEQ)
from p.GetJoinKeys(), allowing joins using `<=>` to be considered for IndexJoin;
update the enumeration to mirror constructIndexJoin by checking the isNullEQ
slice (e.g., any true entry) after calling GetJoinKeys (with outerIdx logic) and
skip/reject building IndexJoin candidates when a null-safe equality is present
so IndexJoin is not admitted for `<=>` semantics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/cherry-pick-not-approved do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants