Skip to content

planner, executor: support access path keep order with IN conditions using merge sort (#62694) | tidb-test=pr/2699 - #66746

Merged
ti-chi-bot[bot] merged 4 commits into
pingcap:release-8.5from
time-and-fate:cherry-pick-62694
Mar 11, 2026
Merged

ti-chi-bot[bot] merged 4 commits into
pingcap:release-8.5from
time-and-fate:cherry-pick-62694

Conversation

@time-and-fate

@time-and-fate time-and-fate commented Mar 6, 2026 •

Copy link
Copy Markdown
Member

Manual cherry-pick of ##62694


What problem does this PR solve?

Issue Number: close #63449 close #34882

Problem Summary:

What changed and how does it work?

  • planner
    • As mentioned in the issue, new fields GroupedRanges and GroupByColIdxs are added to AccessPath, PhysicalIndexScan, and PhysicalTableScan. (pkg/planner/core/operator/physicalop/*)
    • matchProperty() (pkg/planner/core/find_best_task.go)
      • Add the new logic to match the sort property as described in the issue.
    • Due to changes in matchProperty(), the names and data types of several other fields and the function return value are also modified correspondingly, like candidatePath.isMatchProp, matchPropForIndexMergeAlternatives(). The checking logic is also updated correspondingly. (pkg/planner/core/find_best_task.go)
    • When it's PropMatchedNeedMergeSort, set up ByItems, GroupedRanges, and GroupByColIdxs for PhysicalIndexScan and PhysicalTableScan. (convertToIndexScan(), convertToTableScan())
    • New function GroupRangesByCols() that builds/rebuilds the GroupedRanges from the GroupByColIdxs and ranges. (pkg/planner/core/find_best_task.go)
    • Enum PhysicalPropMatchResult (pkg/planner/property/physical_property.go)
      • PropMatchedNeedMergeSort: means the newly introduced enhancement.
    • When rebuilding ranges for the plan cache, also rebuild the GroupedRanges. (pkg/planner/core/plan_cache_rebuild.go)
  • executor
    • In Open() of the 3 executors, when there are correlated columns, also use GroupRangesByCols to rebuild grouped ranges after rebuilding ranges.
    • IndexReaderExecutor
      • New field groupedRanges [][]*ranger.Range, directly comes from PhysicalIndexScan.
      • Update Open() to consider the new case when building kv ranges.
    • IndexLookUpExecutor
      • New field groupedRanges [][]*ranger.Range, directly comes from PhysicalIndexScan.
      • New field groupedKVRanges []*kvRangesWithPhysicalTblID as a unified place to store the kv ranges. It replaces the previous partitionKVRanges and kvRanges field.
      • Update buildTableKeyRanges() to consider the new case when building kv ranges.
    • TableReaderExecutor
      • New field groupedRanges and groupByColIdxs, directly come from PhysicalTableScan.
      • Update Open() to consider the new case when building kv ranges.
      • buildResp() is updated and renamed to buildRespForGroupedRanges() as a unified method to handle ranges and grouped ranges.
    • mem*Reader
      • Correctly set up usedIndex for the extra sorting (mem reader doesn't support merge sort). (pkg/executor/mem_reader.go)
      • When usedIndex is set, it means we need extra sorting. (pkg/executor/mem_reader.go)
      • memIndexLookUpReader
        • New field groupedKVRanges []*kvRangesWithPhysicalTblID as a unified place to store the kv ranges. It replaces the previous partitionKVRanges, partitionTables, and partitionMode fields. It corresponds to the changes in IndexLookUpExecutor.

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

    • Added optimization support for ORDER BY queries using indexed columns with multi-column IN predicates, enabling more efficient execution plans.
  • Performance Improvements

    • Reduced unnecessary sorting operations by leveraging index ordering capabilities.
    • Improved query plan generation for grouped range access patterns, eliminating redundant sort nodes in execution plans.

@ti-chi-bot ti-chi-bot Bot added do-not-merge/cherry-pick-not-approved release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. sig/planner SIG: Planner labels Mar 6, 2026
@coderabbitai

coderabbitai Bot commented Mar 6, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This change implements merge-sort optimization for IN-condition queries to enable "keep order" without requiring a global sort. It adds grouped-range metadata to physical plans, propagates these ranges through executor layers with corresponding KV range information, and implements merge-sort across multiple sorted range groups to satisfy ORDER BY requirements efficiently.

Changes

Cohort / File(s) Summary
Planner Range Grouping
pkg/planner/core/find_best_task.go, pkg/planner/property/physical_property.go, pkg/planner/util/path.go
Introduces GroupRangesByCols function and PhysicalPropMatchResult enum value (PropMatchedNeedMergeSort) to detect and signal merge-sort scenarios; updates property matching logic to return richer match results for grouped range handling in index/table plan selection.
Physical Plan Structure
pkg/planner/core/physical_plans.go
Adds GroupedRanges and GroupByColIdxs fields to PhysicalIndexScan and PhysicalTableScan to store grouped range metadata propagated from planner to executors.
Plan Cache Rebuild
pkg/planner/core/plan_cache_rebuild.go
Rebuilds GroupedRanges from base ranges when GroupByColIdxs is non-empty during buildRangeForTableScan and buildRangeForIndexScan to keep grouped metadata in sync with computed ranges.
Executor Range Grouping and KV Mapping
pkg/executor/builder.go, pkg/executor/distsql.go
Wires grouped ranges and grouped KV ranges from plans to executors; adds collectColIdxFromByItems for sorting decisions and needExtraSorting flag; introduces buildKVRangesForIndexReader and groupedKVRanges field to map KV ranges to physical table IDs for merge-sorted execution.
Table/Index Readers Grouped Range Support
pkg/executor/table_reader.go, pkg/executor/mem_reader.go
Replaces partition-based path logic with needExtraSorting condition; refactors TableReaderExecutor to operate on groupedRanges with per-group KV request generation; updates memIndexLookUpReader to construct and consume groupedKVRanges.
UnionScan Extra Sorting
pkg/executor/union_scan.go
Adds needExtraSorting field to compareExec struct to track when extra sorting is required for keepOrder constraint in partitioned tables or PropMatchedNeedMergeSort scenarios.
Test Expectations
tests/integrationtest/r/planner/core/grouped_ranges_order_by.result, tests/integrationtest/t/planner/core/grouped_ranges_order_by.test
Updates explain output expectations to reflect optimized plans with kept order on range scans and elimination of explicit Sort nodes; adds order_index hints to exercise merge-sort code paths.

Sequence Diagram

sequenceDiagram
    participant Planner as Planner<br/>(find_best_task)
    participant Plan as Physical Plan<br/>(physical_plans)
    participant Executor as Executor<br/>(builder/distsql)
    participant Reader as Range Reader<br/>(table_reader)
    participant KV as KV Layer

    Planner->>Planner: Detect IN-condition<br/>with constant prefix cols
    Planner->>Planner: GroupRangesByCols<br/>(ranges by prefix)
    Planner->>Plan: Set GroupedRanges<br/>& GroupByColIdxs
    Plan-->>Executor: Pass grouped metadata
    Executor->>Executor: Build grouped KV ranges<br/>per physical table
    Executor->>Reader: Create per-group tasks<br/>with needExtraSorting flag
    Reader->>Reader: Generate KV requests<br/>per grouped range
    Reader->>KV: Send multiple sorted<br/>range requests
    KV-->>Reader: Return sorted<br/>results per range
    Reader->>Reader: Merge-sort results<br/>from range groups
    Reader-->>Executor: Deliver globally<br/>ordered rows
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • #66713: Preparatory changes that establish matchProperty refactoring and PropMatchedNeedMergeSort enum; this PR builds on those foundations to wire grouped ranges and merge-sort logic through executors.

Suggested labels

ok-to-test, cherry-pick-approved, type/cherry-pick-for-release-8.5

Suggested reviewers

  • qw4990
  • winoros
  • guo-shaoge

Poem

🐰 ✨ Hopping through ranges, grouped by col,
Merge-sorting streams into one smooth scroll,
No global sort tax on each IN-based bound,
Early limits now fly, keeping order profound!
With KV ranges mapped and kept in line,
Query plans hop forward—oh, so fine! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.14% 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: adding support for keeping order with IN conditions using merge sort. It is specific, concise, and directly related to the core functionality introduced.
Description check ✅ Passed The description adequately covers the problem (issue links), what changed (planner and executor modifications with field additions), and the testing approach (integration test included). All major components are documented.
Linked Issues check ✅ Passed The PR addresses both linked issues: #63449 (merge-sort support for IN with indexed columns) and #34882 (LIMIT pushdown). The implementation adds GroupedRanges/GroupByColIdxs, updates matchProperty logic, and modifies executor scan paths to handle grouped ranges correctly.
Out of Scope Changes check ✅ Passed All changes remain within scope: planner enhancements for grouped ranges, executor modifications for merge-sort support, and test updates. No unrelated functionality or refactoring outside the grouped-range and merge-sort objectives is present.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.5.0)

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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (2)
pkg/executor/table_reader.go (1)

398-449: ⚠️ Potential issue | 🔴 Critical

Preserve e.kvRanges across both split reads.

Open() can invoke this helper twice after SplitRangesAcrossInt64Boundary(), but each branch currently replaces e.kvRanges. Since kvRanges are later consumed by UnionScan, only the last half of an unsigned-handle scan survives and dirty rows from the first half can be missed.

💡 Suggested fix
-			e.kvRanges = sortAndGetKVRangesFromReqs(kvReqs)
+			e.kvRanges = append(e.kvRanges, sortAndGetKVRangesFromReqs(kvReqs)...)

Apply the same append change at each assignment site in buildRespForGroupedRanges().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/executor/table_reader.go` around lines 398 - 449, The code currently
replaces e.kvRanges in multiple places inside buildRespForGroupedRanges(),
losing earlier KV ranges when this helper is called twice; change each
assignment (the three sites that call sortAndGetKVRangesFromReqs and assign to
e.kvRanges) to append to the existing slice instead of overwriting it (e.g.
e.kvRanges = append(e.kvRanges, sortAndGetKVRangesFromReqs(... )...)), ensuring
you handle the nil/empty case safely so previous ranges are preserved for
UnionScan; update the assignments in the TiFlash batch/non-batch branches and
the final assignment accordingly.
pkg/executor/distsql.go (1)

415-421: ⚠️ Potential issue | 🟠 Major

Close already-open SelectResults on mid-loop failure.

If e.SelectResult() fails after one or more earlier iterations succeeded, those earlier results are leaked because e.result is still unset when Open() returns. Close the accumulated results slice before bubbling the error.

Suggested fix
 		var results []distsql.SelectResult
+		cleanup := true
+		defer func() {
+			if !cleanup {
+				return
+			}
+			for _, r := range results {
+				terror.Log(r.Close())
+			}
+		}()
 		for _, kvReq := range kvReqs {
 			result, err := e.SelectResult(ctx, e.dctx, kvReq, exec.RetTypes(e), getPhysicalPlanIDs(e.plans), e.ID())
 			if err != nil {
 				return err
 			}
 			results = append(results, result)
 		}
 		e.result = distsql.NewSortedSelectResults(e.ectx.GetEvalCtx(), results, e.Schema(), e.byItems, e.memTracker)
+		cleanup = false
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/executor/distsql.go` around lines 415 - 421, In the loop that builds the
results slice by calling e.SelectResult (inside the Open method), if a later
e.SelectResult call returns an error, iterate the already-appended results and
call Close() on each to avoid leaking open SelectResult objects before returning
the error; ensure this cleanup runs before returning the error so e.result
remains unset while no SelectResult stays open. Reference: e.SelectResult,
results slice, e.result, Open().
🧹 Nitpick comments (1)
tests/integrationtest/r/planner/core/grouped_ranges_order_by.result (1)

137-176: Add a direct ORDER BY ... LIMIT regression case.

These cases lock in the new merge-sorted order behavior, but the primary user-facing regression here is the limited ordered-read path. A small EXPLAIN ... ORDER BY ... LIMIT N assertion would make future regressions in TopN pushdown / early-stop much easier to catch.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integrationtest/r/planner/core/grouped_ranges_order_by.result` around
lines 137 - 176, Add a compact regression case exercising ORDER BY ... LIMIT to
lock in the merge-sorted early-stop behavior: add an EXPLAIN format='brief' and
a matching execution for a query such as "select c from t2 where a in (1,3) and
b in (1,3) and d < 150 order by c limit 3" (or a similar a/b/c combination used
elsewhere in this file) and assert the plan shows the ordered index access
(IndexRangeScan / IndexReader / IndexLookUp over index:iabc) with keep
order/limit pushdown and that the result returns only the top N rows; place it
near the existing queries that reference
planner__core__grouped_ranges_order_by.t2.c and index:iabc so regressions in
TopN pushdown / early-stop are detected.
🤖 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/executor/distsql.go`:
- Around line 619-630: The loop over physicalIDs incorrectly reassigns the
shared variable ranges (used as the default input) causing overrides from one
partition to leak into subsequent iterations; fix by introducing a per-iteration
variable (e.g., curRanges) initialized to the original ranges, then if
rangeOverrideForPartitionID[physicalID] exists set curRanges = pRange and pass
curRanges into distsql.CommonHandleRangesToKVRanges and
distsql.IndexRangesToKVRangesWithInterruptSignal (instead of mutating the outer
ranges), ensuring each physicalID uses its own ranges copy.

In `@pkg/executor/table_reader.go`:
- Around line 487-494: sortAndGetKVRangesFromReqs currently mutates
kvReq.KeyRanges in place which can change request semantics before SelectResult
runs; instead, for each kvReq create a copy of its KeyRanges (e.g., allocate a
new slice and copy the elements or use a Clone method if available), call
SortByFunc on that copied KeyRanges, then call AppendSelfTo on the copied ranges
to build the returned slice—do not call SortByFunc directly on kvReq.KeyRanges
so SelectResult and e.kvRanges remain unaffected.

In `@pkg/planner/core/find_best_task.go`:
- Line 740: The current pruning uses compareBool on
lhs.matchPropResult.Matched() and rhs.matchPropResult.Matched(), which collapses
PropMatched and PropMatchedNeedMergeSort into the same bucket and can let a
need-merge-sort path wrongly dominate a direct-order path; replace that boolean
comparison with a rank-based comparison of the full
property.PhysicalPropMatchResult enum (e.g., implement
comparePropMatch(lhs.matchPropResult, rhs.matchPropResult) that maps
PropMatched→2, PropMatchedNeedMergeSort→1, others→0 and returns cmp.Compare of
scores) and use its result in place of matchResult while keeping the
compareGlobalIndex(lhs, rhs) usage unchanged so skyline pruning preserves
direct-order matches.

In `@pkg/planner/core/plan_cache_rebuild.go`:
- Around line 391-397: When rebuilding ranges for the PhysicalIndexJoin path,
ensure you refresh ts.GroupedRanges the same way you do for standalone scans:
after the inner scan's ranges are rebuilt (via x.Ranges.Rebuild()/updateRange()
or inside rebuildRange for the index-join branch), if len(ts.GroupByColIdxs) > 0
call GroupRangesByCols(ts.Ranges, ts.GroupByColIdxs) and assign the result to
ts.GroupedRanges, returning any error; apply the same change to the other
similar block noted (lines ~419-425) so grouped-range metadata is never left
stale for cached index-join merge-sort paths.

---

Outside diff comments:
In `@pkg/executor/distsql.go`:
- Around line 415-421: In the loop that builds the results slice by calling
e.SelectResult (inside the Open method), if a later e.SelectResult call returns
an error, iterate the already-appended results and call Close() on each to avoid
leaking open SelectResult objects before returning the error; ensure this
cleanup runs before returning the error so e.result remains unset while no
SelectResult stays open. Reference: e.SelectResult, results slice, e.result,
Open().

In `@pkg/executor/table_reader.go`:
- Around line 398-449: The code currently replaces e.kvRanges in multiple places
inside buildRespForGroupedRanges(), losing earlier KV ranges when this helper is
called twice; change each assignment (the three sites that call
sortAndGetKVRangesFromReqs and assign to e.kvRanges) to append to the existing
slice instead of overwriting it (e.g. e.kvRanges = append(e.kvRanges,
sortAndGetKVRangesFromReqs(... )...)), ensuring you handle the nil/empty case
safely so previous ranges are preserved for UnionScan; update the assignments in
the TiFlash batch/non-batch branches and the final assignment accordingly.

---

Nitpick comments:
In `@tests/integrationtest/r/planner/core/grouped_ranges_order_by.result`:
- Around line 137-176: Add a compact regression case exercising ORDER BY ...
LIMIT to lock in the merge-sorted early-stop behavior: add an EXPLAIN
format='brief' and a matching execution for a query such as "select c from t2
where a in (1,3) and b in (1,3) and d < 150 order by c limit 3" (or a similar
a/b/c combination used elsewhere in this file) and assert the plan shows the
ordered index access (IndexRangeScan / IndexReader / IndexLookUp over
index:iabc) with keep order/limit pushdown and that the result returns only the
top N rows; place it near the existing queries that reference
planner__core__grouped_ranges_order_by.t2.c and index:iabc so regressions in
TopN pushdown / early-stop are detected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e5521cfc-8c9d-40a2-8b72-53aeb4acc333

📥 Commits

Reviewing files that changed from the base of the PR and between 3a27621 and 44e8b99.

📒 Files selected for processing (13)
  • pkg/executor/builder.go
  • pkg/executor/distsql.go
  • pkg/executor/mem_reader.go
  • pkg/executor/table_reader.go
  • pkg/executor/union_scan.go
  • pkg/planner/core/exhaust_physical_plans.go
  • pkg/planner/core/find_best_task.go
  • pkg/planner/core/physical_plans.go
  • pkg/planner/core/plan_cache_rebuild.go
  • pkg/planner/property/physical_property.go
  • pkg/planner/util/path.go
  • tests/integrationtest/r/planner/core/grouped_ranges_order_by.result
  • tests/integrationtest/t/planner/core/grouped_ranges_order_by.test

Comment thread pkg/executor/distsql.go Outdated
Comment thread pkg/executor/table_reader.go
Comment thread pkg/planner/core/find_best_task.go
Comment thread pkg/planner/core/plan_cache_rebuild.go
@codecov

codecov Bot commented Mar 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.51899% with 73 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (release-8.5@3a27621). Learn more about missing BASE report.

Additional details and impacted files
@@               Coverage Diff                @@
##             release-8.5     #66746   +/-   ##
================================================
  Coverage               ?   55.7301%           
================================================
  Files                  ?       1819           
  Lines                  ?     658579           
  Branches               ?          0           
================================================
  Hits                   ?     367027           
  Misses                 ?     265005           
  Partials               ?      26547           
Flag Coverage Δ
integration 39.0841% <78.4810%> (?)
unit 65.8153% <80.2531%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 55.3447% <0.0000%> (?)
parser ∅ <0.0000%> (?)
br 55.4922% <0.0000%> (?)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@time-and-fate time-and-fate changed the title planner, executor: support access path keep order with IN conditions using merge sort (#62694) planner, executor: support access path keep order with IN conditions using merge sort (#62694) | tidb-test=pr/2699 Mar 6, 2026
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
pkg/executor/distsql.go (1)

405-423: ⚠️ Potential issue | 🟠 Major

Close previously opened SelectResults on the merge-sort error path.

If a later buildKVReq() or SelectResult() call fails, every result already appended to results is leaked because open() returns before assigning e.result or closing the partial slice.

Suggested fix
 	} else {
 		// Use sortedSelectResults for merge sort
 		kvReqs := make([]*kv.Request, 0, len(kvRanges))
 		for _, kvRange := range kvRanges {
 			kvReq, err := e.buildKVReq([]kv.KeyRange{kvRange})
 			if err != nil {
 				return err
 			}
 			kvReqs = append(kvReqs, kvReq)
 		}
 		var results []distsql.SelectResult
+		defer func() {
+			if err == nil {
+				return
+			}
+			closeables := make([]Closeable, 0, len(results))
+			for _, result := range results {
+				closeables = append(closeables, result)
+			}
+			terror.Log(closeAll(closeables...))
+		}()
 		for _, kvReq := range kvReqs {
 			result, err := e.SelectResult(ctx, e.dctx, kvReq, exec.RetTypes(e), getPhysicalPlanIDs(e.plans), e.ID())
 			if err != nil {
 				return err
 			}
 			results = append(results, result)
 		}
 		e.result = distsql.NewSortedSelectResults(e.ectx.GetEvalCtx(), results, e.Schema(), e.byItems, e.memTracker)
 	}

As per coding guidelines, "Keep error handling actionable and contextual; avoid silently swallowing errors in Go code".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/executor/distsql.go` around lines 405 - 423, If SelectResult or
buildKVReq fails partway through creating the merge-sort results, previously
appended distsql.SelectResult values in the results slice are leaked; update the
code in the elt that builds kvReqs/results so that on any error you iterate the
accumulated results and call Close() (or the appropriate cleanup method) on each
distsql.SelectResult before returning the error, and only assign e.result via
distsql.NewSortedSelectResults(e.ectx.GetEvalCtx(), results, e.Schema(),
e.byItems, e.memTracker) after all SelectResult calls have succeeded (ensure
buildKVReq, SelectResult, results slice, and e.result are referenced to locate
the fix).
🤖 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/executor/distsql.go`:
- Around line 319-345: buildKVRangesForIndexReader currently flattens
groupedRanges into a single []kv.KeyRange which loses the logical (group ×
partition) stream boundaries; change it to preserve and return grouped KV
streams (e.g. [][]kv.KeyRange) instead of flattening, so each entry corresponds
to one logical stream produced from groupedRanges/tableIDs; update callers
(notably open() and any needMergeSort logic) to compute needMergeSort from the
number of logical streams (stream count) rather than the raw KV range count, and
follow the pattern used by IndexLookUpExecutor.buildTableKeyRanges and
GroupRangesByCols to keep group boundaries intact when invoking buildKeyRanges.

---

Outside diff comments:
In `@pkg/executor/distsql.go`:
- Around line 405-423: If SelectResult or buildKVReq fails partway through
creating the merge-sort results, previously appended distsql.SelectResult values
in the results slice are leaked; update the code in the elt that builds
kvReqs/results so that on any error you iterate the accumulated results and call
Close() (or the appropriate cleanup method) on each distsql.SelectResult before
returning the error, and only assign e.result via
distsql.NewSortedSelectResults(e.ectx.GetEvalCtx(), results, e.Schema(),
e.byItems, e.memTracker) after all SelectResult calls have succeeded (ensure
buildKVReq, SelectResult, results slice, and e.result are referenced to locate
the fix).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7e8acda6-55d6-4431-b6d4-beeb7de22a24

📥 Commits

Reviewing files that changed from the base of the PR and between 44e8b99 and ca88509.

📒 Files selected for processing (1)
  • pkg/executor/distsql.go

Comment thread pkg/executor/distsql.go
@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

2 similar comments
@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@ti-chi-bot ti-chi-bot Bot added approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Mar 9, 2026
@ti-chi-bot

ti-chi-bot Bot commented Mar 9, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: qw4990, winoros

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

The pull request process is described 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 ti-chi-bot Bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Mar 9, 2026
@ti-chi-bot

ti-chi-bot Bot commented Mar 9, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-03-09 02:01:22.114955309 +0000 UTC m=+229113.627012960: ☑️ agreed by qw4990.
  • 2026-03-09 19:16:32.615789511 +0000 UTC m=+291224.127847172: ☑️ agreed by winoros.

@ti-chi-bot ti-chi-bot Bot added cherry-pick-approved Cherry pick PR approved by release team. and removed do-not-merge/cherry-pick-not-approved labels Mar 10, 2026
@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

3 similar comments
@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

9 similar comments
@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@time-and-fate

Copy link
Copy Markdown
Member Author

/retest

@ti-chi-bot
ti-chi-bot Bot merged commit 5182594 into pingcap:release-8.5 Mar 11, 2026
20 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 25, 2026
6 of 12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved cherry-pick-approved Cherry pick PR approved by release team. lgtm 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants