Skip to content

Commit

Permalink
This is an automated cherry-pick of #45617
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
  • Loading branch information
qw4990 authored and ti-chi-bot committed Jul 28, 2023
1 parent 96f6214 commit 00e6563
Showing 1 changed file with 115 additions and 7 deletions.
122 changes: 115 additions & 7 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,7 @@ func filterIndexJoinBySessionVars(sc sessionctx.Context, indexJoins []PhysicalPl
return indexJoins
}

<<<<<<< HEAD
// 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) {
Expand Down Expand Up @@ -2006,6 +2007,50 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
}
}()

=======
func (p *LogicalJoin) preferAny(joinFlags ...uint) bool {
for _, flag := range joinFlags {
if p.preferJoinType&flag > 0 {
return true
}
}
return false
}

const (
joinLeft = 0
joinRight = 1
indexJoinMethod = 0
indexHashJoinMethod = 1
indexMergeJoinMethod = 2
)

func (*LogicalJoin) getIndexJoinSideAndMethod(join PhysicalPlan) (innerSide, joinMethod int, ok bool) {
var innerIdx int
switch ij := join.(type) {
case *PhysicalIndexJoin:
innerIdx = ij.getInnerChildIdx()
joinMethod = indexJoinMethod
case *PhysicalIndexHashJoin:
innerIdx = ij.getInnerChildIdx()
joinMethod = indexHashJoinMethod
case *PhysicalIndexMergeJoin:
innerIdx = ij.getInnerChildIdx()
joinMethod = indexMergeJoinMethod
default:
return 0, 0, false
}
ok = true
innerSide = joinLeft
if innerIdx == 1 {
innerSide = joinRight
}
return
}

// tryToGetIndexJoin returns all available index join plans, and the second returned value indicates whether this plan is enforced by hints.
func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJoins []PhysicalPlan, canForced bool) {
>>>>>>> 79f00016016 (planner: refactor `tryToGetIndexJoin` (#45617))
// supportLeftOuter and supportRightOuter indicates whether this type of join
// supports the left side or right side to be the outer side.
var supportLeftOuter, supportRightOuter bool
Expand All @@ -2017,9 +2062,9 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
case InnerJoin:
supportLeftOuter, supportRightOuter = true, true
}

var allLeftOuterJoins, allRightOuterJoins, forcedLeftOuterJoins, forcedRightOuterJoins []PhysicalPlan
candidates := make([]PhysicalPlan, 0, 2)
if supportLeftOuter {
<<<<<<< HEAD
allLeftOuterJoins = p.getIndexJoinByOuterIdx(prop, 0)
forcedLeftOuterJoins = make([]PhysicalPlan, 0, len(allLeftOuterJoins))
for _, j := range allLeftOuterJoins {
Expand Down Expand Up @@ -2069,16 +2114,79 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
return filterIndexJoinBySessionVars(p.ctx, allRightOuterJoins), false
case len(forcedRightOuterJoins) != 0 && (!supportLeftOuter || (forceRightOuter && !forceLeftOuter)):
return forcedRightOuterJoins, true
}
=======
candidates = append(candidates, p.getIndexJoinByOuterIdx(prop, 0)...)
}
if supportRightOuter {
candidates = append(candidates, p.getIndexJoinByOuterIdx(prop, 1)...)
}

canForceLeft := len(forcedLeftOuterJoins) != 0 && forceLeftOuter
canForceRight := len(forcedRightOuterJoins) != 0 && forceRightOuter
canForced = canForceLeft || canForceRight
// handle hints and variables about index join.
// the priority is: force hints like TIDB_INLJ > filter hints like NO_INDEX_JOIN > variables.
candidates, canForced = p.handleForceIndexJoinHints(prop, candidates)
if canForced {
return append(forcedLeftOuterJoins, forcedRightOuterJoins...), true
return candidates, canForced
}
return filterIndexJoinBySessionVars(p.SCtx(), candidates), false
}

// handleForceIndexJoinHints handles the force index join hints and returns all plans that can satisfy the hints.
func (p *LogicalJoin) handleForceIndexJoinHints(prop *property.PhysicalProperty, candidates []PhysicalPlan) (indexJoins []PhysicalPlan, canForced bool) {
if !p.preferAny(preferRightAsINLJInner, preferRightAsINLHJInner, preferRightAsINLMJInner,
preferLeftAsINLJInner, preferLeftAsINLHJInner, preferLeftAsINLMJInner) {
return candidates, false // no force index join hints
}
forced := make([]PhysicalPlan, 0, len(candidates))
for _, candidate := range candidates {
innerSide, joinMethod, ok := p.getIndexJoinSideAndMethod(candidate)
if !ok {
continue
}
if (p.preferAny(preferLeftAsINLJInner) && innerSide == joinLeft && joinMethod == indexJoinMethod) ||
(p.preferAny(preferRightAsINLJInner) && innerSide == joinRight && joinMethod == indexJoinMethod) ||
(p.preferAny(preferLeftAsINLHJInner) && innerSide == joinLeft && joinMethod == indexHashJoinMethod) ||
(p.preferAny(preferRightAsINLHJInner) && innerSide == joinRight && joinMethod == indexHashJoinMethod) ||
(p.preferAny(preferLeftAsINLMJInner) && innerSide == joinLeft && joinMethod == indexMergeJoinMethod) ||
(p.preferAny(preferRightAsINLMJInner) && innerSide == joinRight && joinMethod == indexMergeJoinMethod) {
forced = append(forced, candidate)
>>>>>>> 79f00016016 (planner: refactor `tryToGetIndexJoin` (#45617))
}
}

if len(forced) > 0 {
return forced, true
}
<<<<<<< HEAD
return filterIndexJoinBySessionVars(p.ctx, append(allLeftOuterJoins, allRightOuterJoins...)), false
=======
// Cannot find any valid index join plan with these force hints.
// 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 prop.IsSortItemEmpty() {
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 p.preferAny(preferLeftAsINLJInner, preferRightAsINLJInner): // prefer index join
errMsg = fmt.Sprintf("Optimizer Hint %s or %s is inapplicable", restore2JoinHint(HintINLJ, indexJoinTables), restore2JoinHint(TiDBIndexNestedLoopJoin, indexJoinTables))
case p.preferAny(preferLeftAsINLHJInner, preferRightAsINLHJInner): // prefer index hash join
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLHJ, indexHashJoinTables))
case p.preferAny(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.
p.SCtx().GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack(errMsg))
}
return candidates, false
>>>>>>> 79f00016016 (planner: refactor `tryToGetIndexJoin` (#45617))
}

func checkChildFitBC(p Plan) bool {
Expand Down

0 comments on commit 00e6563

Please sign in to comment.