Skip to content

Commit 169f60d

Browse files
qw4990ti-chi-bot
authored andcommitted
This is an automated cherry-pick of #45617
Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
1 parent da1e947 commit 169f60d

File tree

1 file changed

+115
-7
lines changed

1 file changed

+115
-7
lines changed

planner/core/exhaust_physical_plans.go

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,7 @@ func filterIndexJoinBySessionVars(sc sessionctx.Context, indexJoins []PhysicalPl
18451845
return indexJoins
18461846
}
18471847

1848+
<<<<<<< HEAD
18481849
// tryToGetIndexJoin will get index join by hints. If we can generate a valid index join by hint, the second return value
18491850
// will be true, which means we force to choose this index join. Otherwise we will select a join algorithm with min-cost.
18501851
func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJoins []PhysicalPlan, canForced bool) {
@@ -1903,6 +1904,50 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
19031904
}
19041905
}()
19051906

1907+
=======
1908+
func (p *LogicalJoin) preferAny(joinFlags ...uint) bool {
1909+
for _, flag := range joinFlags {
1910+
if p.preferJoinType&flag > 0 {
1911+
return true
1912+
}
1913+
}
1914+
return false
1915+
}
1916+
1917+
const (
1918+
joinLeft = 0
1919+
joinRight = 1
1920+
indexJoinMethod = 0
1921+
indexHashJoinMethod = 1
1922+
indexMergeJoinMethod = 2
1923+
)
1924+
1925+
func (*LogicalJoin) getIndexJoinSideAndMethod(join PhysicalPlan) (innerSide, joinMethod int, ok bool) {
1926+
var innerIdx int
1927+
switch ij := join.(type) {
1928+
case *PhysicalIndexJoin:
1929+
innerIdx = ij.getInnerChildIdx()
1930+
joinMethod = indexJoinMethod
1931+
case *PhysicalIndexHashJoin:
1932+
innerIdx = ij.getInnerChildIdx()
1933+
joinMethod = indexHashJoinMethod
1934+
case *PhysicalIndexMergeJoin:
1935+
innerIdx = ij.getInnerChildIdx()
1936+
joinMethod = indexMergeJoinMethod
1937+
default:
1938+
return 0, 0, false
1939+
}
1940+
ok = true
1941+
innerSide = joinLeft
1942+
if innerIdx == 1 {
1943+
innerSide = joinRight
1944+
}
1945+
return
1946+
}
1947+
1948+
// tryToGetIndexJoin returns all available index join plans, and the second returned value indicates whether this plan is enforced by hints.
1949+
func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJoins []PhysicalPlan, canForced bool) {
1950+
>>>>>>> 79f00016016 (planner: refactor `tryToGetIndexJoin` (#45617))
19061951
// supportLeftOuter and supportRightOuter indicates whether this type of join
19071952
// supports the left side or right side to be the outer side.
19081953
var supportLeftOuter, supportRightOuter bool
@@ -1914,9 +1959,9 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
19141959
case InnerJoin:
19151960
supportLeftOuter, supportRightOuter = true, true
19161961
}
1917-
1918-
var allLeftOuterJoins, allRightOuterJoins, forcedLeftOuterJoins, forcedRightOuterJoins []PhysicalPlan
1962+
candidates := make([]PhysicalPlan, 0, 2)
19191963
if supportLeftOuter {
1964+
<<<<<<< HEAD
19201965
allLeftOuterJoins = p.getIndexJoinByOuterIdx(prop, 0)
19211966
forcedLeftOuterJoins = make([]PhysicalPlan, 0, len(allLeftOuterJoins))
19221967
for _, j := range allLeftOuterJoins {
@@ -1966,16 +2011,79 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
19662011
return filterIndexJoinBySessionVars(p.ctx, allRightOuterJoins), false
19672012
case len(forcedRightOuterJoins) != 0 && (!supportLeftOuter || (forceRightOuter && !forceLeftOuter)):
19682013
return forcedRightOuterJoins, true
1969-
}
2014+
=======
2015+
candidates = append(candidates, p.getIndexJoinByOuterIdx(prop, 0)...)
2016+
}
2017+
if supportRightOuter {
2018+
candidates = append(candidates, p.getIndexJoinByOuterIdx(prop, 1)...)
19702019
}
19712020
1972-
canForceLeft := len(forcedLeftOuterJoins) != 0 && forceLeftOuter
1973-
canForceRight := len(forcedRightOuterJoins) != 0 && forceRightOuter
1974-
canForced = canForceLeft || canForceRight
2021+
// handle hints and variables about index join.
2022+
// the priority is: force hints like TIDB_INLJ > filter hints like NO_INDEX_JOIN > variables.
2023+
candidates, canForced = p.handleForceIndexJoinHints(prop, candidates)
19752024
if canForced {
1976-
return append(forcedLeftOuterJoins, forcedRightOuterJoins...), true
2025+
return candidates, canForced
2026+
}
2027+
return filterIndexJoinBySessionVars(p.SCtx(), candidates), false
2028+
}
2029+
2030+
// handleForceIndexJoinHints handles the force index join hints and returns all plans that can satisfy the hints.
2031+
func (p *LogicalJoin) handleForceIndexJoinHints(prop *property.PhysicalProperty, candidates []PhysicalPlan) (indexJoins []PhysicalPlan, canForced bool) {
2032+
if !p.preferAny(preferRightAsINLJInner, preferRightAsINLHJInner, preferRightAsINLMJInner,
2033+
preferLeftAsINLJInner, preferLeftAsINLHJInner, preferLeftAsINLMJInner) {
2034+
return candidates, false // no force index join hints
19772035
}
2036+
forced := make([]PhysicalPlan, 0, len(candidates))
2037+
for _, candidate := range candidates {
2038+
innerSide, joinMethod, ok := p.getIndexJoinSideAndMethod(candidate)
2039+
if !ok {
2040+
continue
2041+
}
2042+
if (p.preferAny(preferLeftAsINLJInner) && innerSide == joinLeft && joinMethod == indexJoinMethod) ||
2043+
(p.preferAny(preferRightAsINLJInner) && innerSide == joinRight && joinMethod == indexJoinMethod) ||
2044+
(p.preferAny(preferLeftAsINLHJInner) && innerSide == joinLeft && joinMethod == indexHashJoinMethod) ||
2045+
(p.preferAny(preferRightAsINLHJInner) && innerSide == joinRight && joinMethod == indexHashJoinMethod) ||
2046+
(p.preferAny(preferLeftAsINLMJInner) && innerSide == joinLeft && joinMethod == indexMergeJoinMethod) ||
2047+
(p.preferAny(preferRightAsINLMJInner) && innerSide == joinRight && joinMethod == indexMergeJoinMethod) {
2048+
forced = append(forced, candidate)
2049+
>>>>>>> 79f00016016 (planner: refactor `tryToGetIndexJoin` (#45617))
2050+
}
2051+
}
2052+
2053+
if len(forced) > 0 {
2054+
return forced, true
2055+
}
2056+
<<<<<<< HEAD
19782057
return filterIndexJoinBySessionVars(p.ctx, append(allLeftOuterJoins, allRightOuterJoins...)), false
2058+
=======
2059+
// Cannot find any valid index join plan with these force hints.
2060+
// Print warning message if any hints cannot work.
2061+
// If the required property is not empty, we will enforce it and try the hint again.
2062+
// So we only need to generate warning message when the property is empty.
2063+
if prop.IsSortItemEmpty() {
2064+
var indexJoinTables, indexHashJoinTables, indexMergeJoinTables []hintTableInfo
2065+
if p.hintInfo != nil {
2066+
t := p.hintInfo.indexNestedLoopJoinTables
2067+
indexJoinTables, indexHashJoinTables, indexMergeJoinTables = t.inljTables, t.inlhjTables, t.inlmjTables
2068+
}
2069+
var errMsg string
2070+
switch {
2071+
case p.preferAny(preferLeftAsINLJInner, preferRightAsINLJInner): // prefer index join
2072+
errMsg = fmt.Sprintf("Optimizer Hint %s or %s is inapplicable", restore2JoinHint(HintINLJ, indexJoinTables), restore2JoinHint(TiDBIndexNestedLoopJoin, indexJoinTables))
2073+
case p.preferAny(preferLeftAsINLHJInner, preferRightAsINLHJInner): // prefer index hash join
2074+
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLHJ, indexHashJoinTables))
2075+
case p.preferAny(preferLeftAsINLMJInner, preferRightAsINLMJInner): // prefer index merge join
2076+
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLMJ, indexMergeJoinTables))
2077+
}
2078+
// Append inapplicable reason.
2079+
if len(p.EqualConditions) == 0 {
2080+
errMsg += " without column equal ON condition"
2081+
}
2082+
// Generate warning message to client.
2083+
p.SCtx().GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack(errMsg))
2084+
}
2085+
return candidates, false
2086+
>>>>>>> 79f00016016 (planner: refactor `tryToGetIndexJoin` (#45617))
19792087
}
19802088
19812089
func checkChildFitBC(p Plan) bool {

0 commit comments

Comments
 (0)