Skip to content

Commit

Permalink
planner: support the leading hint for outer join (#35264)
Browse files Browse the repository at this point in the history
ref #29932
  • Loading branch information
Reminiscent authored Jun 29, 2022
1 parent 680b78c commit 4538cf5
Show file tree
Hide file tree
Showing 4 changed files with 1,417 additions and 94 deletions.
24 changes: 12 additions & 12 deletions planner/core/rule_join_reorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,15 @@ func (s *joinReOrderSolver) optimizeRecursive(ctx sessionctx.Context, p LogicalP
}

if leadingHintInfo != nil && leadingHintInfo.leadingJoinOrder != nil {
if hasOuterJoin {
ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack("leading hint is inapplicable when we have outer join"))
} else {
if useGreedy {
ok, leftJoinGroup := baseGroupSolver.generateLeadingJoinGroup(curJoinGroup, leadingHintInfo)
if !ok {
ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack("leading hint is inapplicable, check if the leading hint table is valid"))
} else {
curJoinGroup = leftJoinGroup
}
if useGreedy {
ok, leftJoinGroup := baseGroupSolver.generateLeadingJoinGroup(curJoinGroup, leadingHintInfo, hasOuterJoin)
if !ok {
ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack("leading hint is inapplicable, check if the leading hint table is valid"))
} else {
ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack("leading hint is inapplicable for the DP join reorder algorithm"))
curJoinGroup = leftJoinGroup
}
} else {
ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInternal.GenWithStack("leading hint is inapplicable for the DP join reorder algorithm"))
}
}

Expand Down Expand Up @@ -298,7 +294,7 @@ type baseSingleGroupJoinOrderSolver struct {
leadingJoinGroup LogicalPlan
}

func (s *baseSingleGroupJoinOrderSolver) generateLeadingJoinGroup(curJoinGroup []LogicalPlan, hintInfo *tableHintInfo) (bool, []LogicalPlan) {
func (s *baseSingleGroupJoinOrderSolver) generateLeadingJoinGroup(curJoinGroup []LogicalPlan, hintInfo *tableHintInfo, hasOuterJoin bool) (bool, []LogicalPlan) {
var leadingJoinGroup []LogicalPlan
leftJoinGroup := make([]LogicalPlan, len(curJoinGroup))
copy(leftJoinGroup, curJoinGroup)
Expand All @@ -324,6 +320,10 @@ func (s *baseSingleGroupJoinOrderSolver) generateLeadingJoinGroup(curJoinGroup [
var usedEdges []*expression.ScalarFunction
var joinType JoinType
leadingJoin, leadingJoinGroup[0], usedEdges, joinType = s.checkConnection(leadingJoin, leadingJoinGroup[0])
if hasOuterJoin && usedEdges == nil {
// If the joinGroups contain the outer join, we disable the cartesian product.
return false, nil
}
leadingJoin, s.otherConds = s.makeJoin(leadingJoin, leadingJoinGroup[0], usedEdges, joinType)
leadingJoinGroup = leadingJoinGroup[1:]
}
Expand Down
42 changes: 19 additions & 23 deletions planner/core/rule_join_reorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,6 @@ func TestLeadingJoinHint(t *testing.T) {
tk.MustExec("create table t8(a int, b int, key(a));")
runJoinReorderTestData(t, tk, "TestLeadingJoinHint")

// test cases for outer join
tk.MustExec("select /*+ leading(t1, t3) */ * from t1 left join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))
tk.MustExec("select /*+ leading(t2) */ * from t1 left join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))
tk.MustExec("select /*+ leading(t2, t3) */ * from t1 left join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))
tk.MustExec("select /*+ leading(t1, t2, t3) */ * from t1 left join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))
tk.MustExec("select /*+ leading(t1, t3) */ * from t1 join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))
tk.MustExec("select /*+ leading(t1, t2) */ * from t1 join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))
tk.MustExec("select /*+ leading(t3) */ * from t1 join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))

// test cases for multiple leading hints
tk.MustExec("select /*+ leading(t1) leading(t2) */ * from t1 join t2 on t1.a=t2.a join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 We can only use one leading hint at most, when multiple leading hints are used, all leading hints will be invalid"))
Expand Down Expand Up @@ -166,13 +150,6 @@ func TestJoinOrderHint(t *testing.T) {
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 There are no matching table names for (t1) in optimizer hint /*+ LEADING(t2, t1) */. Maybe you can use the table alias name",
"Warning 1815 leading hint is inapplicable, check if the leading hint table is valid"))

// conflict between table names
tk.MustExec("select /*+ leading(t3) */ * from t1 join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))

tk.MustExec("select /*+ leading(t1, t3) */ * from t1 join t2 on t1.a=t2.a left join t3 on t2.b=t3.b")
tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1815 leading hint is inapplicable when we have outer join"))

// table name in leading hint cross query block
// Todo: Can not handle this case yet. Because when we extract the join group, it will get the join group {t1, t2, t3}.
// So the table 't4' can not be used.
Expand Down Expand Up @@ -329,3 +306,22 @@ func TestJoinOrderHint4Subquery(t *testing.T) {

runJoinReorderTestData(t, tk, "TestJoinOrderHint4Subquery")
}

func TestLeadingJoinHint4OuterJoin(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()

tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t, t1, t2, t3, t4, t5, t6, t7, t8;")
tk.MustExec("create table t(a int, b int, key(a));")
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));")
tk.MustExec("create table t5(a int, b int, key(a));")
tk.MustExec("create table t6(a int, b int, key(a));")
tk.MustExec("create table t7(a int, b int, key(a));")
tk.MustExec("create table t8(a int, b int, key(a));")
runJoinReorderTestData(t, tk, "TestLeadingJoinHint4OuterJoin")
}
61 changes: 61 additions & 0 deletions planner/core/testdata/join_reorder_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,5 +298,66 @@
"select /*+ leading(t1, t2@sel_2) */ t1.a, (select min(t2.a) from t2) from t1 join t3 on t1.a = t3.a;",
"select /*+ leading(t3, t2@sel_2) */ t1.a, (select min(t2.a) from t2) from t1 join t3 on t1.a = t3.a;"
]
},
{
"name": "TestLeadingJoinHint4OuterJoin",
"cases": [
"select /*+ leading(t3, t2) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t3, t1) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t1, t2) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t3) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t2) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t1) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t3, t2, t1) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t1, t2, t3) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t3, t1, t2) */ * from t2 left join t1 on t2.a=t1.a left join t3 on t1.b=t3.b;",
"select /*+ leading(t2) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t1) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t3) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t2, t1) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t2, t3) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t3, t1) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t2, t1, t3) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t1, t3, t2) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t2, t3, t1) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=1;",
"select /*+ leading(t1) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t2) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t3) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t1, t2) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t3, t2) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t1, t3) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t1, t2, t3) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t3, t1, t2) */ * from t2 left join (t1 left join t3 on t1.a=t3.a) on t2.a=t3.a;",
"select /*+ leading(t1) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t2) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t3) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t4) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t1, t2) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t1, t3) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t4, t1) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t4, t2) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t3, t2) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t3, t4) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t1, t2, t3) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t1, t4, t3) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t4, t2, t3) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t1, t2, t3, t4) */ * from (t1 left join t2 on t1.a=t2.a) left join (t3 left join t4 on t3.a=t4.a) on t2.a=t4.a;",
"select /*+ leading(t1) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t2) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t3) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t4) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t2, t1) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t2, t3) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t4, t1) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t3, t1) */ * from ((select t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select * from ((select /*+ leading(t5) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select * from ((select /*+ leading(t6) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select * from ((select /*+ leading(t5, t7) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select * from ((select /*+ leading(t6, t8, t7) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t3) */ * from ((select /*+ leading(t5) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t3, t1) */ * from ((select /*+ leading(t7) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t3, t1, t2) */ * from ((select /*+ leading(t6, t7) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;",
"select /*+ leading(t3, t4) */ * from ((select /*+ leading(t5, t7, t8) */ t8.a, t8.b from t8, t7, t6, t5 where t5.a = t6.a and t6.b=t7.b) t3 left join t4 on t3.a=t4.a) left join (t1 left join t2 on t1.a=t2.a) on t1.a=t4.a;"
]
}
]
Loading

0 comments on commit 4538cf5

Please sign in to comment.