Skip to content

Commit 0adf0ac

Browse files
authored
planner: refine tryToGetIndexJoin (#45587) (#45712)
ref #45520
1 parent 40cfe57 commit 0adf0ac

File tree

2 files changed

+65
-61
lines changed

2 files changed

+65
-61
lines changed

planner/core/exhaust_physical_plans.go

Lines changed: 62 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,58 +1864,80 @@ func filterIndexJoinBySessionVars(sc sessionctx.Context, indexJoins []PhysicalPl
18641864
return indexJoins
18651865
}
18661866

1867-
// tryToGetIndexJoin will get index join by hints. If we can generate a valid index join by hint, the second return value
1868-
// will be true, which means we force to choose this index join. Otherwise we will select a join algorithm with min-cost.
1869-
func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJoins []PhysicalPlan, canForced bool) {
1870-
inljRightOuter := (p.preferJoinType & preferLeftAsINLJInner) > 0
1871-
inljLeftOuter := (p.preferJoinType & preferRightAsINLJInner) > 0
1872-
hasINLJHint := inljLeftOuter || inljRightOuter
1867+
func (p *LogicalJoin) preferAny(joinFlags ...uint) bool {
1868+
for _, flag := range joinFlags {
1869+
if p.preferJoinType&flag > 0 {
1870+
return true
1871+
}
1872+
}
1873+
return false
1874+
}
18731875

1874-
inlhjRightOuter := (p.preferJoinType & preferLeftAsINLHJInner) > 0
1875-
inlhjLeftOuter := (p.preferJoinType & preferRightAsINLHJInner) > 0
1876-
hasINLHJHint := inlhjLeftOuter || inlhjRightOuter
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
1881+
switch ij := join.(type) {
1882+
case *PhysicalIndexJoin:
1883+
innerIdx = ij.getInnerChildIdx()
1884+
joinMethod = indexJoin
1885+
case *PhysicalIndexHashJoin:
1886+
innerIdx = ij.getInnerChildIdx()
1887+
joinMethod = indexHashJoin
1888+
case *PhysicalIndexMergeJoin:
1889+
innerIdx = ij.getInnerChildIdx()
1890+
joinMethod = indexMergeJoin
1891+
default:
1892+
return false
1893+
}
1894+
innerSide = left
1895+
if innerIdx == 1 {
1896+
innerSide = right
1897+
}
18771898

1878-
inlmjRightOuter := (p.preferJoinType & preferLeftAsINLMJInner) > 0
1879-
inlmjLeftOuter := (p.preferJoinType & preferRightAsINLMJInner) > 0
1880-
hasINLMJHint := inlmjLeftOuter || inlmjRightOuter
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
1908+
}
18811909

1882-
forceLeftOuter := inljLeftOuter || inlhjLeftOuter || inlmjLeftOuter
1883-
forceRightOuter := inljRightOuter || inlhjRightOuter || inlmjRightOuter
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.
1912+
func (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
18841915
needForced := forceLeftOuter || forceRightOuter
18851916

18861917
defer func() {
1887-
// refine error message
1918+
// Print warning message if any hints cannot work.
18881919
// If the required property is not empty, we will enforce it and try the hint again.
18891920
// So we only need to generate warning message when the property is empty.
18901921
if !canForced && needForced && prop.IsSortItemEmpty() {
18911922
// 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+
}
18921928
var errMsg string
18931929
switch {
1894-
case hasINLJHint:
1895-
errMsg = "Optimizer Hint INL_JOIN or TIDB_INLJ is inapplicable"
1896-
case hasINLHJHint:
1897-
errMsg = "Optimizer Hint INL_HASH_JOIN is inapplicable"
1898-
case hasINLMJHint:
1899-
errMsg = "Optimizer Hint INL_MERGE_JOIN is inapplicable"
1900-
}
1901-
if p.hintInfo != nil && p.preferJoinType > 0 {
1902-
t := p.hintInfo.indexNestedLoopJoinTables
1903-
switch {
1904-
case len(t.inljTables) != 0:
1905-
errMsg = fmt.Sprintf("Optimizer Hint %s or %s is inapplicable",
1906-
restore2JoinHint(HintINLJ, t.inljTables), restore2JoinHint(TiDBIndexNestedLoopJoin, t.inljTables))
1907-
case len(t.inlhjTables) != 0:
1908-
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLHJ, t.inlhjTables))
1909-
case len(t.inlmjTables) != 0:
1910-
errMsg = fmt.Sprintf("Optimizer Hint %s is inapplicable", restore2JoinHint(HintINLMJ, t.inlmjTables))
1911-
}
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))
19121936
}
1913-
19141937
// Append inapplicable reason.
19151938
if len(p.EqualConditions) == 0 {
19161939
errMsg += " without column equal ON condition"
19171940
}
1918-
19191941
// Generate warning message to client.
19201942
warning := ErrInternal.GenWithStack(errMsg)
19211943
p.ctx.GetSessionVars().StmtCtx.AppendWarning(warning)
@@ -1939,19 +1961,8 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
19391961
allLeftOuterJoins = p.getIndexJoinByOuterIdx(prop, 0)
19401962
forcedLeftOuterJoins = make([]PhysicalPlan, 0, len(allLeftOuterJoins))
19411963
for _, j := range allLeftOuterJoins {
1942-
switch j.(type) {
1943-
case *PhysicalIndexJoin:
1944-
if inljLeftOuter {
1945-
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j)
1946-
}
1947-
case *PhysicalIndexHashJoin:
1948-
if inlhjLeftOuter {
1949-
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j)
1950-
}
1951-
case *PhysicalIndexMergeJoin:
1952-
if inlmjLeftOuter {
1953-
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j)
1954-
}
1964+
if p.satisfyIndexJoinHint(j) {
1965+
forcedLeftOuterJoins = append(forcedLeftOuterJoins, j)
19551966
}
19561967
}
19571968
switch {
@@ -1961,23 +1972,13 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ
19611972
return forcedLeftOuterJoins, true
19621973
}
19631974
}
1975+
19641976
if supportRightOuter {
19651977
allRightOuterJoins = p.getIndexJoinByOuterIdx(prop, 1)
19661978
forcedRightOuterJoins = make([]PhysicalPlan, 0, len(allRightOuterJoins))
19671979
for _, j := range allRightOuterJoins {
1968-
switch j.(type) {
1969-
case *PhysicalIndexJoin:
1970-
if inljRightOuter {
1971-
forcedRightOuterJoins = append(forcedRightOuterJoins, j)
1972-
}
1973-
case *PhysicalIndexHashJoin:
1974-
if inlhjRightOuter {
1975-
forcedRightOuterJoins = append(forcedRightOuterJoins, j)
1976-
}
1977-
case *PhysicalIndexMergeJoin:
1978-
if inlmjRightOuter {
1979-
forcedRightOuterJoins = append(forcedRightOuterJoins, j)
1980-
}
1980+
if p.satisfyIndexJoinHint(j) {
1981+
forcedRightOuterJoins = append(forcedRightOuterJoins, j)
19811982
}
19821983
}
19831984
switch {

planner/core/planbuilder.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ func restore2TableHint(hintTables ...hintTableInfo) string {
340340
}
341341

342342
func restore2JoinHint(hintType string, hintTables []hintTableInfo) string {
343+
if len(hintTables) == 0 {
344+
return strings.ToUpper(hintType)
345+
}
343346
buffer := bytes.NewBufferString("/*+ ")
344347
buffer.WriteString(strings.ToUpper(hintType))
345348
buffer.WriteString("(")

0 commit comments

Comments
 (0)