@@ -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.
18501851func (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+ >> >> >> > 79 f00016016 (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
19812089func checkChildFitBC(p Plan) bool {
0 commit comments