Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: support no_merge_join hint on optimizer (#45562) #45638

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions planner/core/casetest/rule/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
load("@io_bazel_rules_go//go:def.bzl", "go_test")

go_test(
name = "rule_test",
timeout = "short",
srcs = [
"main_test.go",
"rule_derive_topn_from_window_test.go",
"rule_inject_extra_projection_test.go",
"rule_join_reorder_test.go",
"rule_result_reorder_test.go",
],
data = glob(["testdata/**"]),
flaky = True,
shard_count = 22,
deps = [
"//domain",
"//expression",
"//expression/aggregation",
"//parser/ast",
"//parser/model",
"//parser/mysql",
"//planner/core/internal",
"//sessionctx/variable",
"//testkit",
"//testkit/testdata",
"//testkit/testmain",
"//testkit/testsetup",
"//types",
"//util/mock",
"@com_github_pingcap_failpoint//:failpoint",
"@com_github_stretchr_testify//require",
"@org_uber_go_goleak//:goleak",
],
)
327 changes: 327 additions & 0 deletions planner/core/casetest/rule/rule_join_reorder_test.go

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,15 @@ func (p *LogicalJoin) GetMergeJoin(prop *property.PhysicalProperty, schema *expr
joins = append(joins, mergeJoin)
}
}

if p.preferJoinType&preferNoMergeJoin > 0 {
if p.preferJoinType&preferMergeJoin == 0 {
return nil
}
p.SCtx().GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack(
"Some MERGE_JOIN and NO_MERGE_JOIN hints conflict, NO_MERGE_JOIN is ignored"))
}

// If TiDB_SMJ hint is existed, it should consider enforce merge join,
// because we can't trust lhsChildProperty completely.
if (p.preferJoinType & preferMergeJoin) > 0 {
Expand Down
44 changes: 44 additions & 0 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ const (
TiDBMergeJoin = "tidb_smj"
// HintSMJ is hint enforce merge join.
HintSMJ = "merge_join"
// HintNoMergeJoin is the hint to enforce the query not to use merge join.
HintNoMergeJoin = "no_merge_join"

// TiDBBroadCastJoin indicates applying broadcast join by force.
TiDBBroadCastJoin = "tidb_bcj"
Expand Down Expand Up @@ -594,7 +596,23 @@ func (p *LogicalJoin) setPreferredJoinTypeAndOrder(hintInfo *tableHintInfo) {
if hintInfo.ifPreferMergeJoin(lhsAlias, rhsAlias) {
p.preferJoinType |= preferMergeJoin
}
<<<<<<< HEAD
if hintInfo.ifPreferBroadcastJoin(lhsAlias, rhsAlias) {
=======
if hintInfo.ifPreferMergeJoin(rhsAlias) {
p.preferJoinType |= preferMergeJoin
p.rightPreferJoinType |= preferMergeJoin
}
if hintInfo.ifPreferNoMergeJoin(lhsAlias) {
p.preferJoinType |= preferNoMergeJoin
p.leftPreferJoinType |= preferNoMergeJoin
}
if hintInfo.ifPreferNoMergeJoin(rhsAlias) {
p.preferJoinType |= preferNoMergeJoin
p.rightPreferJoinType |= preferNoMergeJoin
}
if hintInfo.ifPreferBroadcastJoin(lhsAlias) {
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
p.preferJoinType |= preferBCJoin
}
if hintInfo.ifPreferShuffleJoin(lhsAlias, rhsAlias) {
Expand Down Expand Up @@ -3579,6 +3597,10 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev
hints = b.hintProcessor.GetCurrentStmtHints(hints, currentLevel)
var (
sortMergeTables, inljTables, inlhjTables, inlmjTables, hashJoinTables, bcTables []hintTableInfo
<<<<<<< HEAD
=======
noHashJoinTables, noMergeJoinTables []hintTableInfo
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
shuffleJoinTables []hintTableInfo
indexHintList, indexMergeHintList []indexHintInfo
tiflashTables, tikvTables []hintTableInfo
Expand All @@ -3593,7 +3615,11 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev
for _, hint := range hints {
// Set warning for the hint that requires the table name.
switch hint.HintName.L {
<<<<<<< HEAD
case TiDBMergeJoin, HintSMJ, TiDBIndexNestedLoopJoin, HintINLJ, HintINLHJ, HintINLMJ,
=======
case TiDBMergeJoin, HintSMJ, TiDBIndexNestedLoopJoin, HintINLJ, HintINLHJ, HintINLMJ, HintNoHashJoin, HintNoMergeJoin,
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
TiDBHashJoin, HintHJ, HintUseIndex, HintIgnoreIndex, HintForceIndex, HintOrderIndex, HintNoOrderIndex, HintIndexMerge, HintLeading:
if len(hint.Tables) == 0 {
b.pushHintWithoutTableWarning(hint)
Expand All @@ -3616,6 +3642,13 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev
inlmjTables = append(inlmjTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...)
case TiDBHashJoin, HintHJ:
hashJoinTables = append(hashJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...)
<<<<<<< HEAD
=======
case HintNoHashJoin:
noHashJoinTables = append(noHashJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...)
case HintNoMergeJoin:
noMergeJoinTables = append(noMergeJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...)
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
case HintMPP1PhaseAgg:
aggHints.preferAggType |= preferMPP1PhaseAgg
case HintMPP2PhaseAgg:
Expand Down Expand Up @@ -3726,6 +3759,11 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev
shuffleJoinTables: shuffleJoinTables,
indexNestedLoopJoinTables: indexNestedLoopJoinTables{inljTables, inlhjTables, inlmjTables},
hashJoinTables: hashJoinTables,
<<<<<<< HEAD
=======
noHashJoinTables: noHashJoinTables,
noMergeJoinTables: noMergeJoinTables,
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
indexHintList: indexHintList,
tiflashTables: tiflashTables,
tikvTables: tikvTables,
Expand Down Expand Up @@ -6940,6 +6978,12 @@ func getInnerFromParenthesesAndUnaryPlus(expr ast.ExprNode) ast.ExprNode {
// containDifferentJoinTypes checks whether `preferJoinType` contains different
// join types.
func containDifferentJoinTypes(preferJoinType uint) bool {
<<<<<<< HEAD
=======
preferJoinType &= ^preferNoHashJoin
preferJoinType &= ^preferNoMergeJoin

>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
inlMask := preferRightAsINLJInner ^ preferLeftAsINLJInner
inlhjMask := preferRightAsINLHJInner ^ preferLeftAsINLHJInner
inlmjMask := preferRightAsINLMJInner ^ preferLeftAsINLMJInner
Expand Down
19 changes: 19 additions & 0 deletions planner/core/logical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,26 @@ func (tp JoinType) String() string {
}

const (
<<<<<<< HEAD
preferLeftAsINLJInner uint = 1 << iota
=======
// Hint flag for join
preferINLJ uint = 1 << iota
preferINLHJ
preferINLMJ
preferHJBuild
preferHJProbe
preferHashJoin
preferNoHashJoin
preferMergeJoin
preferNoMergeJoin
preferBCJoin
preferShuffleJoin
preferRewriteSemiJoin

// Hint flag to specify the join with direction
preferLeftAsINLJInner
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
preferRightAsINLJInner
preferLeftAsINLHJInner
preferRightAsINLHJInner
Expand Down
16 changes: 16 additions & 0 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ type tableHintInfo struct {
broadcastJoinTables []hintTableInfo
shuffleJoinTables []hintTableInfo
hashJoinTables []hintTableInfo
<<<<<<< HEAD
=======
noHashJoinTables []hintTableInfo
noMergeJoinTables []hintTableInfo
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
indexHintList []indexHintInfo
tiflashTables []hintTableInfo
tikvTables []hintTableInfo
Expand Down Expand Up @@ -237,6 +242,17 @@ func (info *tableHintInfo) ifPreferHashJoin(tableNames ...*hintTableInfo) bool {
return info.matchTableName(tableNames, info.hashJoinTables)
}

<<<<<<< HEAD
=======
func (info *tableHintInfo) ifPreferNoHashJoin(tableNames ...*hintTableInfo) bool {
return info.matchTableName(tableNames, info.noHashJoinTables)
}

func (info *tableHintInfo) ifPreferNoMergeJoin(tableNames ...*hintTableInfo) bool {
return info.matchTableName(tableNames, info.noMergeJoinTables)
}

>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562))
func (info *tableHintInfo) ifPreferHJBuild(tableNames ...*hintTableInfo) bool {
return info.matchTableName(tableNames, info.hjBuildTables)
}
Expand Down
35 changes: 35 additions & 0 deletions planner/core/testdata/join_reorder_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,41 @@
]
},
{
<<<<<<< HEAD:planner/core/testdata/join_reorder_suite_in.json
=======
"name": "TestNoHashJoinHint",
"cases": [
"select /*+ no_hash_join() */ * from t1, t2",
"select /*+ no_hash_join(t1), hash_join(t1) */ * from t1, t2",
"select /*+ no_hash_join(t1), hash_join(t2) */ * from t1, t2",
"select /*+ no_hash_join(t1) */ * from t1, t2",
"select /*+ no_hash_join(t1, t2) */ * from t1, t2",
"select /*+ no_hash_join(t1) */ * from t1, t2 where t1.a=t2.a",
"select /*+ no_hash_join(t1, t2) */ * from t1, t2 where t1.b=t2.b",
"select /*+ no_hash_join(t1) */ * from t1, t2 where t1.a=t2.a and t1.b=t2.b",
"select /*+ no_hash_join(t2) */ * from t1 left join t2 on t1.b=t2.b",
"select /*+ no_hash_join(t2) */ * from t1 left join t2 on t1.a=t2.a",
"select /*+ no_hash_join(t2) */ * from t1 right join t2 on t1.b=t2.b",
"select /*+ no_hash_join(t2) */ * from t1 right join t2 on t1.a=t2.a",
"select /*+ leading(t4, t3, t2, t1), no_hash_join(t2, t3) */ * from t1, t2, t3, t4",
"select /*+ leading(t1, t2, t3, t4), hash_join(t1, t2), no_hash_join(t3), hash_join(t4) */ * from t1, t2, t3, t4"
]
},
{
"name": "TestNoMergeJoinHint",
"cases": [
"select /*+ no_merge_join() */ * from t1, t2 where t1.a=t2.a",
"select /*+ no_merge_join(t1), merge_join(t1) */ * from t1, t2 where t1.a=t2.a",
"select /*+ no_merge_join(t1), merge_join(t2) */ * from t1, t2 where t1.a=t2.a",
"select /*+ no_merge_join(t1) */ * from t1, t2 where t1.a=t2.a",
"select /*+ no_merge_join(t1, t2) */ * from t1, t2 where t1.a=t2.a",
"select /*+ no_merge_join(t2) */ * from t1 right join t2 on t1.a=t2.a",
"select /*+ leading(t4, t3, t2, t1), no_merge_join(t2, t3) */ * from t1, t2, t3, t4 where t1.a=t2.a and t2.a=t3.a and t3.a=t4.a",
"select /*+ leading(t1, t2, t3, t4), merge_join(t1, t2), no_merge_join(t3), merge_join(t4) */ * from t1, t2, t3, t4 where t1.a=t2.a and t2.a=t3.a and t3.a=t4.a"
]
},
{
>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562)):planner/core/casetest/rule/testdata/join_reorder_suite_in.json
"name": "TestLeadingJoinHint",
"cases": [
"select /*+ leading(t, t1) */ * from t, t1, t2, t3 where t.a = t1.a and t1.b=t2.b;",
Expand Down
Loading