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) #45637

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",
],
)
25 changes: 25 additions & 0 deletions planner/core/casetest/rule_join_reorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,31 @@ func TestStraightJoinHint(t *testing.T) {
runJoinReorderTestData(t, tk, "TestStraightJoinHint")
}

<<<<<<< HEAD:planner/core/casetest/rule_join_reorder_test.go
=======
func TestNoHashJoinHint(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t1(a int, b int, key(a));")
tk.MustExec("create table t2(a int, b int, key(a));")
tk.MustExec("create table t3(a int, b int, key(a));")
tk.MustExec("create table t4(a int, b int, key(a));")
runJoinReorderTestData(t, tk, "TestNoHashJoinHint")
}

func TestNoMergeJoinHint(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t1(a int, key(a));")
tk.MustExec("create table t2(a int, key(a));")
tk.MustExec("create table t3(a int, key(a));")
tk.MustExec("create table t4(a int, key(a));")
runJoinReorderTestData(t, tk, "TestNoMergeJoinHint")
}

>>>>>>> ef27b0ef7a6 (planner: support `no_merge_join` hint on optimizer (#45562)):planner/core/casetest/rule/rule_join_reorder_test.go
func TestLeadingJoinHint(t *testing.T) {
store := testkit.CreateMockStore(t)

Expand Down
35 changes: 35 additions & 0 deletions planner/core/casetest/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/casetest/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
315 changes: 315 additions & 0 deletions planner/core/casetest/testdata/join_reorder_suite_out.json

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 @@ -229,6 +229,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
36 changes: 36 additions & 0 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,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 @@ -601,6 +603,14 @@ func (p *LogicalJoin) setPreferredJoinTypeAndOrder(hintInfo *tableHintInfo) {
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) {
p.preferJoinType |= preferBCJoin
p.leftPreferJoinType |= preferBCJoin
Expand Down Expand Up @@ -3710,6 +3720,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 @@ -3724,7 +3738,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 @@ -3747,6 +3765,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 @@ -3857,6 +3882,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 @@ -7062,6 +7092,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
1 change: 1 addition & 0 deletions planner/core/logical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const (
preferHJProbe
preferHashJoin
preferMergeJoin
preferNoMergeJoin
preferBCJoin
preferShuffleJoin
preferRewriteSemiJoin
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