-
Notifications
You must be signed in to change notification settings - Fork 6k
planner: refine tryToGetIndexJoin
#45587
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
Changes from 5 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1969,61 +1969,75 @@ func filterIndexJoinBySessionVars(sc sessionctx.Context, indexJoins []PhysicalPl | |
return indexJoins | ||
} | ||
|
||
func (p *LogicalJoin) prefer(joinFlags ...uint) bool { | ||
for _, flag := range joinFlags { | ||
if p.preferJoinType&flag > 0 { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// canPassJoinHint returns whether this join plan can pass current join hints. | ||
func (p *LogicalJoin) canPassJoinHint(join PhysicalPlan, leftOuter bool) bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest renaming it like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can also use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good suggestion, updated. |
||
const left, right = 0, 1 | ||
const indexJoin, indexHashJoin, indexMergeJoin = 0, 1, 2 | ||
innerSide := left | ||
if leftOuter { | ||
innerSide = right | ||
} | ||
joinMethod := indexJoin | ||
switch join.(type) { | ||
case *PhysicalIndexHashJoin: | ||
joinMethod = indexHashJoin | ||
case *PhysicalIndexMergeJoin: | ||
joinMethod = indexMergeJoin | ||
} | ||
|
||
if (p.prefer(preferLeftAsINLJInner) && innerSide == left && joinMethod == indexJoin) || | ||
(p.prefer(preferRightAsINLJInner) && innerSide == right && joinMethod == indexJoin) || | ||
(p.prefer(preferLeftAsINLHJInner) && innerSide == left && joinMethod == indexHashJoin) || | ||
(p.prefer(preferRightAsINLHJInner) && innerSide == right && joinMethod == indexHashJoin) || | ||
(p.prefer(preferLeftAsINLMJInner) && innerSide == left && joinMethod == indexMergeJoin) || | ||
(p.prefer(preferRightAsINLMJInner) && innerSide == right && joinMethod == indexMergeJoin) { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// tryToGetIndexJoin will get index join by hints. If we can generate a valid index join by hint, the second return value | ||
// will be true, which means we force to choose this index join. Otherwise we will select a join algorithm with min-cost. | ||
func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJoins []PhysicalPlan, canForced bool) { | ||
inljRightOuter := (p.preferJoinType & preferLeftAsINLJInner) > 0 | ||
inljLeftOuter := (p.preferJoinType & preferRightAsINLJInner) > 0 | ||
hasINLJHint := inljLeftOuter || inljRightOuter | ||
|
||
inlhjRightOuter := (p.preferJoinType & preferLeftAsINLHJInner) > 0 | ||
inlhjLeftOuter := (p.preferJoinType & preferRightAsINLHJInner) > 0 | ||
hasINLHJHint := inlhjLeftOuter || inlhjRightOuter | ||
|
||
inlmjRightOuter := (p.preferJoinType & preferLeftAsINLMJInner) > 0 | ||
inlmjLeftOuter := (p.preferJoinType & preferRightAsINLMJInner) > 0 | ||
hasINLMJHint := inlmjLeftOuter || inlmjRightOuter | ||
|
||
forceLeftOuter := inljLeftOuter || inlhjLeftOuter || inlmjLeftOuter | ||
forceRightOuter := inljRightOuter || inlhjRightOuter || inlmjRightOuter | ||
forceLeftOuter := p.prefer(preferRightAsINLJInner, preferRightAsINLHJInner, preferRightAsINLMJInner) // left as outer == right as inner | ||
forceRightOuter := p.prefer(preferLeftAsINLJInner, preferLeftAsINLHJInner, preferLeftAsINLMJInner) // right as outer == left as inner | ||
needForced := forceLeftOuter || forceRightOuter | ||
|
||
defer func() { | ||
// refine error message | ||
// Print warning message if any hints cannot work. | ||
// If the required property is not empty, we will enforce it and try the hint again. | ||
// So we only need to generate warning message when the property is empty. | ||
if !canForced && needForced && prop.IsSortItemEmpty() { | ||
// Construct warning message prefix. | ||
var indexJoinTables, indexHashJoinTables, indexMergeJoinTables []hintTableInfo | ||
if p.hintInfo != nil { | ||
t := p.hintInfo.indexNestedLoopJoinTables | ||
indexJoinTables, indexHashJoinTables, indexMergeJoinTables = t.inljTables, t.inlhjTables, t.inlmjTables | ||
} | ||
var errMsg string | ||
switch { | ||
case hasINLJHint: | ||
errMsg = "Optimizer Hint INL_JOIN or TIDB_INLJ is inapplicable" | ||
case hasINLHJHint: | ||
errMsg = "Optimizer Hint INL_HASH_JOIN is inapplicable" | ||
case hasINLMJHint: | ||
errMsg = "Optimizer Hint INL_MERGE_JOIN is inapplicable" | ||
} | ||
if p.hintInfo != nil && p.preferJoinType > 0 { | ||
t := p.hintInfo.indexNestedLoopJoinTables | ||
switch { | ||
case len(t.inljTables) != 0 && ((p.preferJoinType&preferLeftAsINLJInner > 0) || (p.preferJoinType&preferRightAsINLJInner > 0)): | ||
errMsg = fmt.Sprintf("Optimizer Hint %s or %s is inapplicable", | ||
restore2JoinHint(HintINLJ, t.inljTables), restore2JoinHint(TiDBIndexNestedLoopJoin, t.inljTables)) | ||
case len(t.inlhjTables) != 0 && ((p.preferJoinType&preferLeftAsINLHJInner > 0) || (p.preferJoinType&preferRightAsINLHJInner > 0)): | ||
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLHJ, t.inlhjTables)) | ||
case len(t.inlmjTables) != 0 && ((p.preferJoinType&preferLeftAsINLMJInner > 0) || (p.preferJoinType&preferRightAsINLMJInner > 0)): | ||
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLMJ, t.inlmjTables)) | ||
} | ||
case p.prefer(preferLeftAsINLJInner, preferRightAsINLJInner): // prefer index join | ||
errMsg = fmt.Sprintf("Optimizer Hint %s or %s is inapplicable", restore2JoinHint(HintINLJ, indexJoinTables), restore2JoinHint(TiDBIndexNestedLoopJoin, indexJoinTables)) | ||
case p.prefer(preferLeftAsINLHJInner, preferRightAsINLHJInner): // prefer index hash join | ||
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLHJ, indexHashJoinTables)) | ||
case p.prefer(preferLeftAsINLMJInner, preferRightAsINLMJInner): // prefer index merge join | ||
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLMJ, indexMergeJoinTables)) | ||
} | ||
|
||
// Append inapplicable reason. | ||
if len(p.EqualConditions) == 0 { | ||
errMsg += " without column equal ON condition" | ||
} | ||
|
||
// Generate warning message to client. | ||
warning := ErrInternal.GenWithStack(errMsg) | ||
p.SCtx().GetSessionVars().StmtCtx.AppendWarning(warning) | ||
p.SCtx().GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack(errMsg)) | ||
} | ||
}() | ||
|
||
|
@@ -2044,19 +2058,8 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ | |
allLeftOuterJoins = p.getIndexJoinByOuterIdx(prop, 0) | ||
forcedLeftOuterJoins = make([]PhysicalPlan, 0, len(allLeftOuterJoins)) | ||
for _, j := range allLeftOuterJoins { | ||
switch j.(type) { | ||
case *PhysicalIndexJoin: | ||
if inljLeftOuter { | ||
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j) | ||
} | ||
case *PhysicalIndexHashJoin: | ||
if inlhjLeftOuter { | ||
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j) | ||
} | ||
case *PhysicalIndexMergeJoin: | ||
if inlmjLeftOuter { | ||
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j) | ||
} | ||
if p.canPassJoinHint(j, true) { | ||
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j) | ||
} | ||
} | ||
switch { | ||
|
@@ -2066,23 +2069,13 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ | |
return forcedLeftOuterJoins, true | ||
} | ||
} | ||
|
||
if supportRightOuter { | ||
allRightOuterJoins = p.getIndexJoinByOuterIdx(prop, 1) | ||
forcedRightOuterJoins = make([]PhysicalPlan, 0, len(allRightOuterJoins)) | ||
for _, j := range allRightOuterJoins { | ||
switch j.(type) { | ||
case *PhysicalIndexJoin: | ||
if inljRightOuter { | ||
forcedRightOuterJoins = append(forcedRightOuterJoins, j) | ||
} | ||
case *PhysicalIndexHashJoin: | ||
if inlhjRightOuter { | ||
forcedRightOuterJoins = append(forcedRightOuterJoins, j) | ||
} | ||
case *PhysicalIndexMergeJoin: | ||
if inlmjRightOuter { | ||
forcedRightOuterJoins = append(forcedRightOuterJoins, j) | ||
} | ||
if p.canPassJoinHint(j, false) { | ||
forcedRightOuterJoins = append(forcedRightOuterJoins, j) | ||
} | ||
} | ||
switch { | ||
|
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.
Suggest renaming it like
preferAny
to make it more clear.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