-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
planner: unify OR type IndexMerge code paths #58396
planner: unify OR type IndexMerge code paths #58396
Conversation
…-need-rewrite-or-last
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #58396 +/- ##
================================================
+ Coverage 73.5209% 73.5860% +0.0650%
================================================
Files 1681 1680 -1
Lines 464398 466965 +2567
================================================
+ Hits 341430 343621 +2191
- Misses 102138 102455 +317
- Partials 20830 20889 +59
Flags with carried forward coverage won't be shown. Click here to find out more.
|
…-need-rewrite-or-last
…-need-rewrite-or-last
/retest |
if !needConsiderIndexMerge { | ||
return "IndexMerge is inapplicable or disabled. ", nil // IndexMerge is inapplicable | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this limitation only applies to non-MV indexes, and now the MV index path is also generated here, as said in the design doc, we modify this limitation a little and move it to the end of this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It causes some extra unnecessary work now. This is also why there are new records in pkg/planner/cardinality/testdata/cardinality_suite_out.json
and tests/integrationtest/r/imdbload.result
.
continue | ||
} | ||
// in this loop we do two things. | ||
// 1: If all the partialPaths use the same index, we will not use the indexMerge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to buildIntoAccessPath()
in indexmerge_unfinished_path.go
.
} | ||
// in this loop we do two things. | ||
// 1: If all the partialPaths use the same index, we will not use the indexMerge. | ||
// 2: Compute a theoretical best countAfterAccess(pick its accessConds) for every alternative path(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already moved into indexmerge_unfinished_path.go
as estimateCountAfterAccessForIndexMergeOR()
in the previous PR.
// identify whether all pushedDownCNFItems are fully used. | ||
// If any partial path contains table filters, we need to keep the whole DNF filter in the Selection. | ||
if len(partialPath.TableFilters) > 0 { | ||
needSelection = true | ||
partialPath.TableFilters = nil | ||
} | ||
// If any partial path's index filter cannot be pushed to TiKV, we should keep the whole DNF filter. | ||
if len(partialPath.IndexFilters) != 0 && !expression.CanExprsPushDown(pushDownCtx, partialPath.IndexFilters, kv.TiKV) { | ||
needSelection = true | ||
// Clear IndexFilter, the whole filter will be put in indexMergePath.TableFilters. | ||
partialPath.IndexFilters = nil | ||
} | ||
// Keep this filter as a part of table filters for safety if it has any parameter. | ||
if expression.MaybeOverOptimized4PlanCache(ds.SCtx().GetExprCtx(), cnfItems) { | ||
needSelection = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to buildIntoAccessPath()
in indexmerge_unfinished_path.go
.
if expression.CanExprsPushDown(pushDownCtx, []expression.Expression{cnfItem}, kv.TiKV) { | ||
pushedDownCNFItems = append(pushedDownCNFItems, cnfItem) | ||
} else { | ||
shouldKeepCurrentFilter = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In initUnfinishedPathsFromExpr()
:
- For "case 1": It's already in
generateNormalIndexPartialPath()
so we don't need to add it again. - For "case 2" and "case 3": I added a similar check. Though I'm not sure if it's really needed, I added it anyway.
needSelection = len(remainingFilters) > 0 || len(unfinishedPath.idxColHasUsableFilter) > 0 | ||
needSelection = len(remainingFilters) > 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the check at L211. If you look at it carefully, they are essentially the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
pkg/planner/core/indexmerge_path.go
Outdated
// generateIndexMerge4ComposedIndex generates index path composed of multi indexes including multivalued index from | ||
// (json_member_of / json_overlaps / json_contains) and single-valued index from normal indexes. | ||
// generateANDIndexMerge4ComposedIndex tries to generate AND type index merge AccessPath for ( | ||
//json_member_of / json_overlaps / json_contains) on multiple multi-valued or normal indexes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this formatted by the go fmt
? I thought it would always keep a space here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
This is formatted by GoLand's "wrap on typing", which is not very clever sometimes. It won't add a space in such places.
Actually, go fmt
also won't add this space.
Maybe you fill it in as well for future archaeology. |
tests/integrationtest/r/planner/core/casetest/physicalplantest/physical_plan.result
Show resolved
Hide resolved
Updated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rest LGTM
results = append(results, newPath) | ||
} else { | ||
results[0] = newPath | ||
results = results[:1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any notes for removing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
My original idea is that the row count estimation logic should reflect the advantage of the empty range.
Anyway, I added this logic to the new implementation in the latest commit.
Probably it's better to keep things unchanged as much as possible in such a refactor.
if finishedIndexMergePath != nil { | ||
mvIndexPaths = append(mvIndexPaths, finishedIndexMergePath) | ||
} | ||
if !containMVPath { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems tricky, but fine for now
@time-and-fate: The following test failed, say
Full PR test history. Your PR dashboard. 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. |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: AilinKid, Rustin170506 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
[LGTM Timeline notifier]Timeline:
|
@@ -16,6 +16,7 @@ package core | |||
|
|||
import ( | |||
"cmp" | |||
"github.com/pingcap/tidb/pkg/sessionctx/variable" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
group imports
What problem does this PR solve?
Issue Number: ref #58361
What changed and how does it work?
Now
generateORIndexMerge()
inindexmerge_unfinished_path.go
becomes the new entry for generating all OR type IndexMerge paths. All previous code paths are merged into this one.Entry points
generateIndexMergeOrPaths()
(the code path 1 mentioned in the issue) is modified, moved toindexmerge_unfinished_path.go
, and becomes the newgenerateORIndexMerge()
.generateIndexMergeOnDNF4MVIndex()
andgenerateIndexMerge4ComposedIndex()
(the code paths 2 and 3) are deleted and replaced by the new entry. If you look into the implementation, the code is almost the same as the newgenerateORIndexMerge()
.generateIndexMergePath()
for a simple overview.Some details in unifying the code paths
generateIndexMergeOrPaths()
becomes the newgenerateORIndexMerge()
, some logic in this function is deleted:CanExprsPushDown()
check partially becomes the existing same check ingenerateNormalIndexPartialPath()
, partially becomes the newly added check ininitUnfinishedPathsFromExpr()
.buildIntoAccessPath()
AccessPath.CountAfterAccess
is replaced byestimateCountAfterAccessForIndexMergeOR()
which is introduced in the previous PR.AccessPath.TableFilters
,AccessPath.IndexFilters
and theMaybeOverOptimized4PlanCache()
check inmatchPropForIndexMergeAlternatives()
andgenerateNormalIndexPartialPath()
are almost the same. They are unified and moved tobuildIntoAccessPath()
.accessPathsForConds()
candidatePaths
is a slice. That is deleted now, so we can simplifyaccessPathsForConds()
to only receive one*util.AccessPath
and return one*util.AccessPath
.cmpAlternatives()
now.needConsiderIndexMerge
logic ingenerateIndexMerge4NormalIndex()
(which becomesgenerateOtherIndexMerge()
now) is modified.Utils
pkg/planner/util/misc.go
, a util functionSliceRecursiveFlattenIter()
is added to iterate over multi-dimensional slices more elegantly. Otherwise, there will be some 5-level nested code blocks in this PR.Check List
Tests
Side effects
Documentation
Release note
Please refer to Release Notes Language Style Guide to write a quality release note.