Skip to content

Conversation

@elsa0520
Copy link
Contributor

@elsa0520 elsa0520 commented Jan 12, 2026

What problem does this PR solve?

Issue Number: Fix #63280

Problem Summary:

What changed and how does it work?

The planner part 1 of the partial order by enhancement

  1. The new physical property
    • PartialOrderInfo: save the order by columns info
  2. The exhaust physical plan of TopN will add a new path with this new physical property
    • the scope will be limited, and it will only affect the available query patterns when the OptPartialOrderedIndexForTopN is turned on.
  3. The new match property function "matchPartialOrderProperty" is used to check if prefix index can be used for TopN query
    • The restrictions on match properties with new physical properties will be relaxed.
    • Allows prefix index to match ORDER BY columns.
    • The index can completely match the prefix of the order by column.

Check List

Tests

I will add more test after finish the part2 of this enhancement

  • 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

@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 12, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot bot added do-not-merge/needs-linked-issue do-not-merge/needs-tests-checked release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. sig/planner SIG: Planner labels Jan 12, 2026
@tiprow
Copy link

tiprow bot commented Jan 12, 2026

Hi @elsa0520. Thanks for your PR.

PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test all.

I understand the commands that are listed here.

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.

@elsa0520 elsa0520 marked this pull request as ready for review January 13, 2026 08:54
@ti-chi-bot ti-chi-bot bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 13, 2026
@hawkingrei
Copy link
Member

/ok-to-test

Comment on lines +326 to +329
type PartialOrderInfo struct {
// SortItems are the ORDER BY columns from TopN
SortItems []*SortItem
}
Copy link
Member

Choose a reason for hiding this comment

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

type PartialOrderInfo []*SortItem

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the future, it maybe need to add a new field named "limit number" inside of struct PartialOrderInfo.
Because we need to know which is order by column , also we need to know What number of the limit N we can short cut.
So I keep the struct instead of use []*sortItem directly

}
}
}

Copy link
Member

Choose a reason for hiding this comment

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

Also, the case where there's a projection?

And, I think that we can not support the partial order with txn's dirty writes in the first implementation?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, projection is possible. Is it expected that we bail out for Projection?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The dirty write already fixed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it expected that we bail out for Projection?

There can indeed be projection between top and ds. However, the presence of projection doesn't necessarily guarantee the use of a prefix index.

For example, consider the query select fn(a) as a1 from t order by fn(a) limit 10.

In this case, whether an order-preserving index can be used depends entirely on the scalar function of fn(a). Our current code doesn't actually have this capability.

In other words, this query can't even use the index a, let alone the prefix (a).

Copy link
Contributor

Choose a reason for hiding this comment

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

what if select a+b, a, b from t order by a,b limit 10?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I already tried this case. The topn is under the projection because we have a rule named "PushDownTopN(topN)"

@elsa0520 elsa0520 changed the title planner: add the partial order index as candidate for topn optimization planner: add the prefix index as candidate for topn optimization Jan 14, 2026
continue
}
// Check if candidate path need to consider partial order optimization
considerPartialOrderIndex := ds.SCtx().GetSessionVars().OptPartialOrderedIndexForTopN && prop.PartialOrderInfo != nil
Copy link
Contributor

@qw4990 qw4990 Jan 15, 2026

Choose a reason for hiding this comment

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

Should we make the judge here more precise? For example, just call matchPartialOrderProperty to check whether the index can match the partial order property, matchPartialOrderIndex := ds.SCtx().GetSessionVars().OptPartialOrderedIndexForTopN && matchPartialOrderProperty(path, prop) != nil. Then we can avoid putting some unnecessary indexes into our index candidates.

Copy link
Contributor

Choose a reason for hiding this comment

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

Otherwise, if we enable OptPartialOrderedIndexForTopN and there is a PartialOrderInfo, then all indexes are going to be put into our candidates, the if-branch below seems to stop working.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And the partial order skyline pruning at the begin of here ~

Copy link
Contributor

@qw4990 qw4990 left a comment

Choose a reason for hiding this comment

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

Others LGTM, please address these comments before merging it.

@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 15, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: qw4990

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 approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jan 15, 2026
@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 15, 2026

[LGTM Timeline notifier]

Timeline:

  • 2026-01-15 06:55:13.973429008 +0000 UTC m=+44941.587385864: ☑️ agreed by qw4990.

}
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, projection is possible. Is it expected that we bail out for Projection?

type PartialOrderMatchResult struct {
// Matched indicates whether the index can provide partial order
Matched bool
// PrefixColId is the last and only one prefix column ID of index
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you give an example of this field? The comment is hard to understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

if !(len(path.AccessConds) > 0 || !prop.IsSortItemEmpty() || path.Forced || path.IsSingleScan || !considerPartialOrderIndex) {
continue
}

Copy link
Contributor

Choose a reason for hiding this comment

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

This is counter intuitive, hard to follow.
Should be this:

if len(path.AccessConds) > 0 || !prop.IsSortItemEmpty() || path.Forced || path.IsSingleScan || !considerPartialOrderIndex {
    currentCandidate = getIndexCandidate(ds, path, prop)
} else {
    continue
}

Copy link
Contributor

Choose a reason for hiding this comment

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

+1...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is counter intuitive, hard to follow. Should be this:

if len(path.AccessConds) > 0 || !prop.IsSortItemEmpty() || path.Forced || path.IsSingleScan || !considerPartialOrderIndex {
    currentCandidate = getIndexCandidate(ds, path, prop)
} else {
    continue
}

Agree with you change... but the origin logic is like that .... I can change it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

// We will use index to generate physical plan if any of the following conditions is satisfied:
// 1. This path's access cond is not nil.
// 2. We have a non-empty prop to match.
// 3. This index is forced to choose.
// 4. The needed columns are all covered by index columns(and handleCol).
// 5. Has PartialOrderInfo physical property to be considered for partial order optimization (new condition).
if !(len(path.AccessConds) > 0 || !prop.IsSortItemEmpty() || path.Forced || path.IsSingleScan || !considerPartialOrderIndex) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, is this wrong? Should !considerPartialOrderIndex be considerPartialOrderIndex?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This logic is so hard to understand, let me rephrase it in a way that's human-readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

// partialOrderInfo: sortItems: [a, b]
// The partialOrderInfo property will pass through to the datasource and try to matchPartialOrderProperty such as:
// index: (a, b(10) )
PartialOrderInfo *PartialOrderInfo
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we extend PhysicalProperty.HashCode() to incorporate PartialOrderInfo (columns + order direction) so task caching is correct?

@codecov
Copy link

codecov bot commented Jan 15, 2026

Codecov Report

❌ Patch coverage is 67.91444% with 60 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.2034%. Comparing base (6b3f20a) to head (87ba3d2).
⚠️ Report is 59 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #65533        +/-   ##
================================================
- Coverage   78.4730%   76.2034%   -2.2697%     
================================================
  Files          1938       1922        -16     
  Lines        534229     546361     +12132     
================================================
- Hits         419226     416346      -2880     
- Misses       113483     129970     +16487     
+ Partials       1520         45      -1475     
Flag Coverage Δ
integration 41.5933% <23.5294%> (-6.5789%) ⬇️
unit 76.1346% <67.9144%> (-0.3490%) ⬇️

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

Components Coverage Δ
dumpling 56.7974% <ø> (+0.1783%) ⬆️
parser ∅ <ø> (∅)
br 42.4684% <ø> (-22.4202%) ⬇️
🚀 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.

@ti-chi-bot ti-chi-bot bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jan 15, 2026
@elsa0520
Copy link
Contributor Author

/test mysql-test

@tiprow
Copy link

tiprow bot commented Jan 15, 2026

@elsa0520: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test fast_test_tiprow
/test tidb_parser_test

Use /test all to run all jobs.

Details

In response to this:

/test mysql-test

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

ti-chi-bot bot commented Jan 15, 2026

[FORMAT CHECKER NOTIFICATION]

Notice: To remove the do-not-merge/needs-tests-checked label, please finished the tests then check the finished items in description.

For example:

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

📖 For more info, you can check the "Contribute Code" section in the development guide.

@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 15, 2026

@elsa0520: 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
pull-integration-realcluster-test-next-gen 87ba3d2 link true /test pull-integration-realcluster-test-next-gen
pull-integration-ddl-test 87ba3d2 link true /test pull-integration-ddl-test
idc-jenkins-ci-tidb/unit-test 87ba3d2 link true /test unit-test

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.

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

Labels

approved do-not-merge/needs-tests-checked needs-1-more-lgtm Indicates a PR needs 1 more LGTM. 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/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

planner: utilize prefix of columns in order-limit clause to avoid full table scan in join queries

5 participants