From 69bd8f04e6f3f120c4286003d1cbe91353ecb1dc Mon Sep 17 00:00:00 2001 From: Kenan Yao Date: Fri, 15 Jan 2021 11:57:29 +0800 Subject: [PATCH] cherry pick #22392 to release-4.0 Signed-off-by: ti-srebot --- expression/testdata/partition_pruner_out.json | 6 +- planner/core/integration_test.go | 24 +++++++ planner/core/logical_plan_builder.go | 3 +- .../core/testdata/integration_suite_in.json | 8 +++ .../core/testdata/integration_suite_out.json | 62 ++++++++++++++++--- 5 files changed, 91 insertions(+), 12 deletions(-) diff --git a/expression/testdata/partition_pruner_out.json b/expression/testdata/partition_pruner_out.json index 7ef3d5de72524..bd8d23c8dc045 100644 --- a/expression/testdata/partition_pruner_out.json +++ b/expression/testdata/partition_pruner_out.json @@ -46,9 +46,9 @@ { "SQL": "explain select * from t1 left join t2 on t1.id = 1 and t2.a = 2 where t2.id = 7", "Result": [ - "HashJoin_9 1.00 root CARTESIAN inner join", - "├─Point_Get_12(Build) 1.00 root table:t2, partition:p9, index:PRIMARY(id, a) ", - "└─Point_Get_11(Probe) 1.00 root table:t1, partition:p1 handle:1" + "HashJoin_10 1.00 root CARTESIAN inner join", + "├─Point_Get_13(Build) 1.00 root table:t2, partition:p9, index:PRIMARY(id, a) ", + "└─Point_Get_12(Probe) 1.00 root table:t1, partition:p1 handle:1" ] }, { diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index dadb9a24cc1a9..a7c59062a35b8 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -1661,3 +1661,27 @@ func (s *testIntegrationSuite) TestIssue22105(c *C) { tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) } } + +func (s *testIntegrationSuite) TestReorderSimplifiedOuterJoins(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t1,t2,t3") + tk.MustExec("create table t1 (pk char(32) primary key, col1 char(32), col2 varchar(40), col3 char(32), key (col1), key (col3), key (col2,col3), key (col1,col3))") + tk.MustExec("create table t2 (pk char(32) primary key, col1 varchar(100))") + tk.MustExec("create table t3 (pk char(32) primary key, keycol varchar(100), pad1 tinyint(1) default null, pad2 varchar(40), key (keycol,pad1,pad2))") + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 9fa7cb4757813..f859cbc4234a4 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -628,6 +628,8 @@ func (b *PlanBuilder) buildJoin(ctx context.Context, joinNode *ast.Join) (Logica } b.optFlag = b.optFlag | flagPredicatePushDown + // Add join reorder flag regardless of inner join or outer join. + b.optFlag = b.optFlag | flagJoinReOrder leftPlan, err := b.buildResultSetNode(ctx, joinNode.Left) if err != nil { @@ -663,7 +665,6 @@ func (b *PlanBuilder) buildJoin(ctx context.Context, joinNode *ast.Join) (Logica joinPlan.JoinType = RightOuterJoin resetNotNullFlag(joinPlan.schema, 0, leftPlan.Schema().Len()) default: - b.optFlag = b.optFlag | flagJoinReOrder joinPlan.JoinType = InnerJoin } diff --git a/planner/core/testdata/integration_suite_in.json b/planner/core/testdata/integration_suite_in.json index ba43b0748de5a..3a325f45ad46f 100644 --- a/planner/core/testdata/integration_suite_in.json +++ b/planner/core/testdata/integration_suite_in.json @@ -169,5 +169,13 @@ "cases": [ "explain SELECT /*+ use_index_merge(t1)*/ COUNT(*) FROM t1 WHERE (key4=42 AND key6 IS NOT NULL) OR (key1=4 AND key3=6)" ] + }, + { + "name": "TestReorderSimplifiedOuterJoins", + "cases": [ + // Query with INNER JOIN or LEFT JOIN should have the same plan. + "EXPLAIN SELECT t1.pk FROM t1 INNER JOIN t2 ON t1.col1 = t2.pk INNER JOIN t3 ON t1.col3 = t3.pk WHERE t2.col1 IN ('a' , 'b') AND t3.keycol = 'c' AND t1.col2 = 'a' AND t1.col1 != 'abcdef' AND t1.col1 != 'aaaaaa'", + "EXPLAIN SELECT t1.pk FROM t1 LEFT JOIN t2 ON t1.col1 = t2.pk LEFT JOIN t3 ON t1.col3 = t3.pk WHERE t2.col1 IN ('a' , 'b') AND t3.keycol = 'c' AND t1.col2 = 'a' AND t1.col1 != 'abcdef' AND t1.col1 != 'aaaaaa'" + ] } ] diff --git a/planner/core/testdata/integration_suite_out.json b/planner/core/testdata/integration_suite_out.json index 3394d3df1f483..095703884bf00 100644 --- a/planner/core/testdata/integration_suite_out.json +++ b/planner/core/testdata/integration_suite_out.json @@ -50,14 +50,15 @@ { "SQL": "explain select * from t t1 left join t t2 on t1.a=t2.a where from_unixtime(t2.b);", "Plan": [ - "HashJoin_7 9990.00 root inner join, equal:[eq(test.t.a, test.t.a)]", - "├─Selection_15(Build) 7992.00 root from_unixtime(cast(test.t.b))", - "│ └─TableReader_14 7992.00 root data:Selection_13", - "│ └─Selection_13 7992.00 cop[tikv] not(isnull(test.t.a))", - "│ └─TableFullScan_12 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", - "└─TableReader_11(Probe) 9990.00 root data:Selection_10", - " └─Selection_10 9990.00 cop[tikv] not(isnull(test.t.a))", - " └─TableFullScan_9 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + "Projection_7 9990.00 root test.t.a, test.t.b, test.t.a, test.t.b", + "└─HashJoin_9 9990.00 root inner join, equal:[eq(test.t.a, test.t.a)]", + " ├─Selection_13(Build) 7992.00 root from_unixtime(cast(test.t.b))", + " │ └─TableReader_12 7992.00 root data:Selection_11", + " │ └─Selection_11 7992.00 cop[tikv] not(isnull(test.t.a))", + " │ └─TableFullScan_10 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + " └─TableReader_16(Probe) 9990.00 root data:Selection_15", + " └─Selection_15 9990.00 cop[tikv] not(isnull(test.t.a))", + " └─TableFullScan_14 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" ] } ] @@ -904,5 +905,50 @@ ] } ] + }, + { + "Name": "TestReorderSimplifiedOuterJoins", + "Cases": [ + { + "SQL": "EXPLAIN SELECT t1.pk FROM t1 INNER JOIN t2 ON t1.col1 = t2.pk INNER JOIN t3 ON t1.col3 = t3.pk WHERE t2.col1 IN ('a' , 'b') AND t3.keycol = 'c' AND t1.col2 = 'a' AND t1.col1 != 'abcdef' AND t1.col1 != 'aaaaaa'", + "Plan": [ + "IndexJoin_18 13.81 root inner join, inner:IndexLookUp_17, outer key:test.t1.col1, inner key:test.t2.pk, equal cond:eq(test.t1.col1, test.t2.pk)", + "├─IndexJoin_53(Build) 12.50 root inner join, inner:IndexLookUp_52, outer key:test.t3.pk, inner key:test.t1.col3, equal cond:eq(test.t3.pk, test.t1.col3)", + "│ ├─IndexLookUp_80(Build) 10.00 root ", + "│ │ ├─IndexRangeScan_78(Build) 10.00 cop[tikv] table:t3, index:keycol(keycol, pad1, pad2) range:[\"c\",\"c\"], keep order:false, stats:pseudo", + "│ │ └─TableRowIDScan_79(Probe) 10.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ └─IndexLookUp_52(Probe) 1.25 root ", + "│ ├─Selection_50(Build) 1.81 cop[tikv] not(isnull(test.t1.col3))", + "│ │ └─IndexRangeScan_48 1.81 cop[tikv] table:t1, index:col2(col2, col3) range: decided by [eq(test.t1.col3, test.t3.pk) eq(test.t1.col2, a)], keep order:false, stats:pseudo", + "│ └─Selection_51(Probe) 1.25 cop[tikv] ne(test.t1.col1, \"aaaaaa\"), ne(test.t1.col1, \"abcdef\"), not(isnull(test.t1.col1))", + "│ └─TableRowIDScan_49 1.81 cop[tikv] table:t1 keep order:false, stats:pseudo", + "└─IndexLookUp_17(Probe) 1.00 root ", + " ├─Selection_15(Build) 1.00 cop[tikv] ne(test.t2.pk, \"aaaaaa\"), ne(test.t2.pk, \"abcdef\")", + " │ └─IndexRangeScan_13 1.00 cop[tikv] table:t2, index:PRIMARY(pk) range: decided by [eq(test.t2.pk, test.t1.col1)], keep order:false, stats:pseudo", + " └─Selection_16(Probe) 1.00 cop[tikv] in(test.t2.col1, \"a\", \"b\")", + " └─TableRowIDScan_14 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo" + ] + }, + { + "SQL": "EXPLAIN SELECT t1.pk FROM t1 LEFT JOIN t2 ON t1.col1 = t2.pk LEFT JOIN t3 ON t1.col3 = t3.pk WHERE t2.col1 IN ('a' , 'b') AND t3.keycol = 'c' AND t1.col2 = 'a' AND t1.col1 != 'abcdef' AND t1.col1 != 'aaaaaa'", + "Plan": [ + "IndexJoin_18 13.81 root inner join, inner:IndexLookUp_17, outer key:test.t1.col1, inner key:test.t2.pk, equal cond:eq(test.t1.col1, test.t2.pk)", + "├─IndexJoin_53(Build) 12.50 root inner join, inner:IndexLookUp_52, outer key:test.t3.pk, inner key:test.t1.col3, equal cond:eq(test.t3.pk, test.t1.col3)", + "│ ├─IndexLookUp_80(Build) 10.00 root ", + "│ │ ├─IndexRangeScan_78(Build) 10.00 cop[tikv] table:t3, index:keycol(keycol, pad1, pad2) range:[\"c\",\"c\"], keep order:false, stats:pseudo", + "│ │ └─TableRowIDScan_79(Probe) 10.00 cop[tikv] table:t3 keep order:false, stats:pseudo", + "│ └─IndexLookUp_52(Probe) 1.25 root ", + "│ ├─Selection_50(Build) 1.81 cop[tikv] not(isnull(test.t1.col3))", + "│ │ └─IndexRangeScan_48 1.81 cop[tikv] table:t1, index:col2(col2, col3) range: decided by [eq(test.t1.col3, test.t3.pk) eq(test.t1.col2, a)], keep order:false, stats:pseudo", + "│ └─Selection_51(Probe) 1.25 cop[tikv] ne(test.t1.col1, \"aaaaaa\"), ne(test.t1.col1, \"abcdef\"), not(isnull(test.t1.col1))", + "│ └─TableRowIDScan_49 1.81 cop[tikv] table:t1 keep order:false, stats:pseudo", + "└─IndexLookUp_17(Probe) 1.00 root ", + " ├─Selection_15(Build) 1.00 cop[tikv] ne(test.t2.pk, \"aaaaaa\"), ne(test.t2.pk, \"abcdef\")", + " │ └─IndexRangeScan_13 1.00 cop[tikv] table:t2, index:PRIMARY(pk) range: decided by [eq(test.t2.pk, test.t1.col1)], keep order:false, stats:pseudo", + " └─Selection_16(Probe) 1.00 cop[tikv] in(test.t2.col1, \"a\", \"b\")", + " └─TableRowIDScan_14 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo" + ] + } + ] } ]