@@ -1873,77 +1873,39 @@ func (p *LogicalJoin) preferAny(joinFlags ...uint) bool {
18731873 return false
18741874}
18751875
1876- // satisfyIndexJoinHint returns whether this join plan can satisfy current index join hints.
1877- func (p * LogicalJoin ) satisfyIndexJoinHint (join PhysicalPlan ) bool {
1878- const left , right = 0 , 1
1879- const indexJoin , indexHashJoin , indexMergeJoin = 0 , 1 , 2
1880- var innerSide , innerIdx , joinMethod int
1876+ const (
1877+ joinLeft = 0
1878+ joinRight = 1
1879+ indexJoinMethod = 0
1880+ indexHashJoinMethod = 1
1881+ indexMergeJoinMethod = 2
1882+ )
1883+
1884+ func (* LogicalJoin ) getIndexJoinSideAndMethod (join PhysicalPlan ) (innerSide , joinMethod int , ok bool ) {
1885+ var innerIdx int
18811886 switch ij := join .(type ) {
18821887 case * PhysicalIndexJoin :
18831888 innerIdx = ij .getInnerChildIdx ()
1884- joinMethod = indexJoin
1889+ joinMethod = indexJoinMethod
18851890 case * PhysicalIndexHashJoin :
18861891 innerIdx = ij .getInnerChildIdx ()
1887- joinMethod = indexHashJoin
1892+ joinMethod = indexHashJoinMethod
18881893 case * PhysicalIndexMergeJoin :
18891894 innerIdx = ij .getInnerChildIdx ()
1890- joinMethod = indexMergeJoin
1895+ joinMethod = indexMergeJoinMethod
18911896 default :
1892- return false
1897+ return 0 , 0 , false
18931898 }
1894- innerSide = left
1899+ ok = true
1900+ innerSide = joinLeft
18951901 if innerIdx == 1 {
1896- innerSide = right
1902+ innerSide = joinRight
18971903 }
1898-
1899- if (p .preferAny (preferLeftAsINLJInner ) && innerSide == left && joinMethod == indexJoin ) ||
1900- (p .preferAny (preferRightAsINLJInner ) && innerSide == right && joinMethod == indexJoin ) ||
1901- (p .preferAny (preferLeftAsINLHJInner ) && innerSide == left && joinMethod == indexHashJoin ) ||
1902- (p .preferAny (preferRightAsINLHJInner ) && innerSide == right && joinMethod == indexHashJoin ) ||
1903- (p .preferAny (preferLeftAsINLMJInner ) && innerSide == left && joinMethod == indexMergeJoin ) ||
1904- (p .preferAny (preferRightAsINLMJInner ) && innerSide == right && joinMethod == indexMergeJoin ) {
1905- return true
1906- }
1907- return false
1904+ return
19081905}
19091906
1910- // tryToGetIndexJoin will get index join by hints. If we can generate a valid index join by hint, the second return value
1911- // will be true, which means we force to choose this index join. Otherwise we will select a join algorithm with min-cost.
1907+ // tryToGetIndexJoin returns all available index join plans, and the second returned value indicates whether this plan is enforced by hints.
19121908func (p * LogicalJoin ) tryToGetIndexJoin (prop * property.PhysicalProperty ) (indexJoins []PhysicalPlan , canForced bool ) {
1913- forceLeftOuter := p .preferAny (preferRightAsINLJInner , preferRightAsINLHJInner , preferRightAsINLMJInner ) // left as outer == right as inner
1914- forceRightOuter := p .preferAny (preferLeftAsINLJInner , preferLeftAsINLHJInner , preferLeftAsINLMJInner ) // right as outer == left as inner
1915- needForced := forceLeftOuter || forceRightOuter
1916-
1917- defer func () {
1918- // Print warning message if any hints cannot work.
1919- // If the required property is not empty, we will enforce it and try the hint again.
1920- // So we only need to generate warning message when the property is empty.
1921- if ! canForced && needForced && prop .IsSortItemEmpty () {
1922- // Construct warning message prefix.
1923- var indexJoinTables , indexHashJoinTables , indexMergeJoinTables []hintTableInfo
1924- if p .hintInfo != nil {
1925- t := p .hintInfo .indexNestedLoopJoinTables
1926- indexJoinTables , indexHashJoinTables , indexMergeJoinTables = t .inljTables , t .inlhjTables , t .inlmjTables
1927- }
1928- var errMsg string
1929- switch {
1930- case p .preferAny (preferLeftAsINLJInner , preferRightAsINLJInner ): // prefer index join
1931- errMsg = fmt .Sprintf ("Optimizer Hint %s or %s is inapplicable" , restore2JoinHint (HintINLJ , indexJoinTables ), restore2JoinHint (TiDBIndexNestedLoopJoin , indexJoinTables ))
1932- case p .preferAny (preferLeftAsINLHJInner , preferRightAsINLHJInner ): // prefer index hash join
1933- errMsg = fmt .Sprintf ("Optimizer Hint %s is inapplicable" , restore2JoinHint (HintINLHJ , indexHashJoinTables ))
1934- case p .preferAny (preferLeftAsINLMJInner , preferRightAsINLMJInner ): // prefer index merge join
1935- errMsg = fmt .Sprintf ("Optimizer Hint %s is inapplicable" , restore2JoinHint (HintINLMJ , indexMergeJoinTables ))
1936- }
1937- // Append inapplicable reason.
1938- if len (p .EqualConditions ) == 0 {
1939- errMsg += " without column equal ON condition"
1940- }
1941- // Generate warning message to client.
1942- warning := ErrInternal .GenWithStack (errMsg )
1943- p .ctx .GetSessionVars ().StmtCtx .AppendWarning (warning )
1944- }
1945- }()
1946-
19471909 // supportLeftOuter and supportRightOuter indicates whether this type of join
19481910 // supports the left side or right side to be the outer side.
19491911 var supportLeftOuter , supportRightOuter bool
@@ -1955,47 +1917,75 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
19551917 case InnerJoin :
19561918 supportLeftOuter , supportRightOuter = true , true
19571919 }
1958-
1959- var allLeftOuterJoins , allRightOuterJoins , forcedLeftOuterJoins , forcedRightOuterJoins []PhysicalPlan
1920+ candidates := make ([]PhysicalPlan , 0 , 2 )
19601921 if supportLeftOuter {
1961- allLeftOuterJoins = p .getIndexJoinByOuterIdx (prop , 0 )
1962- forcedLeftOuterJoins = make ([]PhysicalPlan , 0 , len (allLeftOuterJoins ))
1963- for _ , j := range allLeftOuterJoins {
1964- if p .satisfyIndexJoinHint (j ) {
1965- forcedLeftOuterJoins = append (forcedLeftOuterJoins , j )
1966- }
1922+ candidates = append (candidates , p .getIndexJoinByOuterIdx (prop , 0 )... )
1923+ }
1924+ if supportRightOuter {
1925+ candidates = append (candidates , p .getIndexJoinByOuterIdx (prop , 1 )... )
1926+ }
1927+
1928+ // handle hints and variables about index join.
1929+ // the priority is: force hints like TIDB_INLJ > filter hints like NO_INDEX_JOIN > variables.
1930+ candidates , canForced = p .handleForceIndexJoinHints (prop , candidates )
1931+ if canForced {
1932+ return candidates , canForced
1933+ }
1934+ return filterIndexJoinBySessionVars (p .SCtx (), candidates ), false
1935+ }
1936+
1937+ // handleForceIndexJoinHints handles the force index join hints and returns all plans that can satisfy the hints.
1938+ func (p * LogicalJoin ) handleForceIndexJoinHints (prop * property.PhysicalProperty , candidates []PhysicalPlan ) (indexJoins []PhysicalPlan , canForced bool ) {
1939+ if ! p .preferAny (preferRightAsINLJInner , preferRightAsINLHJInner , preferRightAsINLMJInner ,
1940+ preferLeftAsINLJInner , preferLeftAsINLHJInner , preferLeftAsINLMJInner ) {
1941+ return candidates , false // no force index join hints
1942+ }
1943+ forced := make ([]PhysicalPlan , 0 , len (candidates ))
1944+ for _ , candidate := range candidates {
1945+ innerSide , joinMethod , ok := p .getIndexJoinSideAndMethod (candidate )
1946+ if ! ok {
1947+ continue
19671948 }
1968- switch {
1969- case len (forcedLeftOuterJoins ) == 0 && ! supportRightOuter :
1970- return filterIndexJoinBySessionVars (p .ctx , allLeftOuterJoins ), false
1971- case len (forcedLeftOuterJoins ) != 0 && (! supportRightOuter || (forceLeftOuter && ! forceRightOuter )):
1972- return forcedLeftOuterJoins , true
1949+ if (p .preferAny (preferLeftAsINLJInner ) && innerSide == joinLeft && joinMethod == indexJoinMethod ) ||
1950+ (p .preferAny (preferRightAsINLJInner ) && innerSide == joinRight && joinMethod == indexJoinMethod ) ||
1951+ (p .preferAny (preferLeftAsINLHJInner ) && innerSide == joinLeft && joinMethod == indexHashJoinMethod ) ||
1952+ (p .preferAny (preferRightAsINLHJInner ) && innerSide == joinRight && joinMethod == indexHashJoinMethod ) ||
1953+ (p .preferAny (preferLeftAsINLMJInner ) && innerSide == joinLeft && joinMethod == indexMergeJoinMethod ) ||
1954+ (p .preferAny (preferRightAsINLMJInner ) && innerSide == joinRight && joinMethod == indexMergeJoinMethod ) {
1955+ forced = append (forced , candidate )
19731956 }
19741957 }
19751958
1976- if supportRightOuter {
1977- allRightOuterJoins = p .getIndexJoinByOuterIdx (prop , 1 )
1978- forcedRightOuterJoins = make ([]PhysicalPlan , 0 , len (allRightOuterJoins ))
1979- for _ , j := range allRightOuterJoins {
1980- if p .satisfyIndexJoinHint (j ) {
1981- forcedRightOuterJoins = append (forcedRightOuterJoins , j )
1982- }
1959+ if len (forced ) > 0 {
1960+ return forced , true
1961+ }
1962+ // Cannot find any valid index join plan with these force hints.
1963+ // Print warning message if any hints cannot work.
1964+ // If the required property is not empty, we will enforce it and try the hint again.
1965+ // So we only need to generate warning message when the property is empty.
1966+ if prop .IsSortItemEmpty () {
1967+ var indexJoinTables , indexHashJoinTables , indexMergeJoinTables []hintTableInfo
1968+ if p .hintInfo != nil {
1969+ t := p .hintInfo .indexNestedLoopJoinTables
1970+ indexJoinTables , indexHashJoinTables , indexMergeJoinTables = t .inljTables , t .inlhjTables , t .inlmjTables
19831971 }
1972+ var errMsg string
19841973 switch {
1985- case len (forcedRightOuterJoins ) == 0 && ! supportLeftOuter :
1986- return filterIndexJoinBySessionVars (p .ctx , allRightOuterJoins ), false
1987- case len (forcedRightOuterJoins ) != 0 && (! supportLeftOuter || (forceRightOuter && ! forceLeftOuter )):
1988- return forcedRightOuterJoins , true
1974+ case p .preferAny (preferLeftAsINLJInner , preferRightAsINLJInner ): // prefer index join
1975+ errMsg = fmt .Sprintf ("Optimizer Hint %s or %s is inapplicable" , restore2JoinHint (HintINLJ , indexJoinTables ), restore2JoinHint (TiDBIndexNestedLoopJoin , indexJoinTables ))
1976+ case p .preferAny (preferLeftAsINLHJInner , preferRightAsINLHJInner ): // prefer index hash join
1977+ errMsg = fmt .Sprintf ("Optimizer Hint %s is inapplicable" , restore2JoinHint (HintINLHJ , indexHashJoinTables ))
1978+ case p .preferAny (preferLeftAsINLMJInner , preferRightAsINLMJInner ): // prefer index merge join
1979+ errMsg = fmt .Sprintf ("Optimizer Hint %s is inapplicable" , restore2JoinHint (HintINLMJ , indexMergeJoinTables ))
19891980 }
1981+ // Append inapplicable reason.
1982+ if len (p .EqualConditions ) == 0 {
1983+ errMsg += " without column equal ON condition"
1984+ }
1985+ // Generate warning message to client.
1986+ p .SCtx ().GetSessionVars ().StmtCtx .AppendWarning (ErrInternal .GenWithStack (errMsg ))
19901987 }
1991-
1992- canForceLeft := len (forcedLeftOuterJoins ) != 0 && forceLeftOuter
1993- canForceRight := len (forcedRightOuterJoins ) != 0 && forceRightOuter
1994- canForced = canForceLeft || canForceRight
1995- if canForced {
1996- return append (forcedLeftOuterJoins , forcedRightOuterJoins ... ), true
1997- }
1998- return filterIndexJoinBySessionVars (p .ctx , append (allLeftOuterJoins , allRightOuterJoins ... )), false
1988+ return candidates , false
19991989}
20001990
20011991func checkChildFitBC (p Plan ) bool {
0 commit comments