From ba5835c232be666589ed40f82d505cd9ec37cec5 Mon Sep 17 00:00:00 2001 From: justarandomstring <847426363@qq.com> Date: Tue, 15 Oct 2019 16:42:03 +0800 Subject: [PATCH] planner, expression: fix simplify outer join with cast (#12701) --- expression/expression.go | 2 +- planner/core/physical_plan_test.go | 37 + planner/core/testdata/plan_suite_in.json | 491 ++++++++ planner/core/testdata/plan_suite_out.json | 1254 +++++++++++++++++++++ 4 files changed, 1783 insertions(+), 1 deletion(-) create mode 100644 planner/core/testdata/plan_suite_in.json create mode 100644 planner/core/testdata/plan_suite_out.json diff --git a/expression/expression.go b/expression/expression.go index 8144950252ed7..5fe938c0aa6cd 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -276,7 +276,7 @@ func EvaluateExprWithNull(ctx sessionctx.Context, schema *Schema, expr Expressio for i, arg := range x.GetArgs() { args[i] = EvaluateExprWithNull(ctx, schema, arg) } - return NewFunctionInternal(ctx, x.FuncName.L, types.NewFieldType(mysql.TypeTiny), args...) + return NewFunctionInternal(ctx, x.FuncName.L, x.RetType, args...) case *Column: if !schema.Contains(x) { return x diff --git a/planner/core/physical_plan_test.go b/planner/core/physical_plan_test.go index 3d1bce80e281d..85aec275ff646 100644 --- a/planner/core/physical_plan_test.go +++ b/planner/core/physical_plan_test.go @@ -1393,3 +1393,40 @@ func (s *testPlanSuite) TestUnmatchedTableInHint(c *C) { } } } + +func (s *testPlanSuite) TestSimplifyOuterJoinWithCast(c *C) { + defer testleak.AfterTest(c)() + store, dom, err := newStoreWithBootstrap() + c.Assert(err, IsNil) + defer func() { + dom.Close() + store.Close() + }() + se, err := session.CreateSession4Test(store) + c.Assert(err, IsNil) + _, err = se.Execute(context.Background(), "use test") + c.Assert(err, IsNil) + + var input []string + var output []struct { + SQL string + Best string + } + s.testData.GetTestCases(c, &input, &output) + for i, test := range input { + comment := Commentf("case:%v sql:%s", i, test) + stmt, err := s.ParseOneStmt(test, "", "") + c.Assert(err, IsNil, comment) + + p, err := planner.Optimize(context.Background(), se, stmt, s.is) + c.Assert(err, IsNil) + s.testData.OnRecord(func() { + output[i].SQL = test + output[i].Best = core.ToString(p) + }) + c.Assert(core.ToString(p), Equals, output[i].Best) + + warnings := se.GetSessionVars().StmtCtx.GetWarnings() + c.Assert(warnings, HasLen, 0, comment) + } +} diff --git a/planner/core/testdata/plan_suite_in.json b/planner/core/testdata/plan_suite_in.json new file mode 100644 index 0000000000000..6c4fcbae7c956 --- /dev/null +++ b/planner/core/testdata/plan_suite_in.json @@ -0,0 +1,491 @@ +[ + { + "name": "TestHintScope", + "cases": [ + // join hints + "select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(t3) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ SM_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ SM_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + // aggregation hints + "select /*+ STREAM_AGG() */ s, count(s) from (select /*+ HASH_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "select /*+ HASH_AGG() */ s, count(s) from (select /*+ STREAM_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "select /*+ HASH_AGG() */ s, count(s) from (select sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "select /*+ STREAM_AGG() */ s, count(s) from (select sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s" + ] + }, + { + "name": "TestIndexHint", + "cases": [ + // simple case + "select /*+ USE_INDEX(t, c_d_e) */ * from t", + "select /*+ IGNORE_INDEX(t, c_d_e) */ c from t order by c", + "select /*+ USE_INDEX(t, c_d_e) */ * from t t1", + "select /*+ IGNORE_INDEX(t, c_d_e) */ t1.c from t t1 order by t1.c", + "select /*+ USE_INDEX(t1, c_d_e) */ * from t t1", + "select /*+ IGNORE_INDEX(t1, c_d_e) */ t1.c from t t1 order by t1.c", + "select /*+ USE_INDEX(t1, c_d_e), USE_INDEX(t2, f) */ * from t t1, t t2 where t1.a = t2.b", + "select /*+ IGNORE_INDEX(t1, c_d_e), IGNORE_INDEX(t2, f), HASH_JOIN(t1) */ * from t t1, t t2 where t1.a = t2.b", + // test multiple indexes + "select /*+ USE_INDEX(t, c_d_e, f, g) */ * from t order by f", + // use TablePath when the hint only contains table. + "select /*+ USE_INDEX(t) */ f from t where f > 10", + // there will be a warning instead of error when index not exist + "select /*+ USE_INDEX(t, no_such_index) */ * from t", + "select /*+ IGNORE_INDEX(t, no_such_index) */ * from t", + // use both use_index and ignore_index, same as index hints in sql. + "select /*+ USE_INDEX(t, c_d_e), IGNORE_INDEX(t, f) */ c from t order by c", + "select /*+ USE_INDEX(t, f), IGNORE_INDEX(t, f) */ c from t order by c", + "select /*+ USE_INDEX(t, c_d_e), IGNORE_INDEX(t, c_d_e) */ c from t order by c", + "select /*+ USE_INDEX(t, c_d_e, f), IGNORE_INDEX(t, c_d_e) */ c from t order by c" + ] + }, + { + "name": "TestDAGPlanBuilderSimpleCase", + "cases":[ + // Test index hint. + "select * from t t1 use index(c_d_e)", + "select f from t use index() where f = 1", + // Test ts + Sort vs. DoubleRead + filter. + "select a from t where a between 1 and 2 order by c", + // Test DNF condition + Double Read. + "select * from t where (t.c > 0 and t.c < 2) or (t.c > 4 and t.c < 6) or (t.c > 8 and t.c < 10) or (t.c > 12 and t.c < 14) or (t.c > 16 and t.c < 18)", + "select * from t where (t.c > 0 and t.c < 1) or (t.c > 2 and t.c < 3) or (t.c > 4 and t.c < 5) or (t.c > 6 and t.c < 7) or (t.c > 9 and t.c < 10)", + // Test TopN to table branch in double read. + "select * from t where t.c = 1 and t.e = 1 order by t.b limit 1", + // Test Null Range + "select * from t where t.e_str is null", + // Test Null Range but the column has not null flag. + "select * from t where t.c is null", + // Test TopN to index branch in double read. + "select * from t where t.c = 1 and t.e = 1 order by t.e limit 1", + // Test TopN to Limit in double read. + "select * from t where t.c = 1 and t.e = 1 order by t.d limit 1", + // Test TopN to Limit in index single read. + "select c from t where t.c = 1 and t.e = 1 order by t.d limit 1", + // Test TopN to Limit in table single read. + "select c from t order by t.a limit 1", + // Test TopN push down in table single read. + "select c from t order by t.a + t.b limit 1", + // Test Limit push down in table single read. + "select c from t limit 1", + // Test Limit push down in index single read. + "select c from t where c = 1 limit 1", + // Test index single read and Selection. + "select c from t where c = 1", + // Test index single read and Sort. + "select c from t order by c", + // Test index single read and Sort. + "select c from t where c = 1 order by e", + // Test Limit push down in double single read. + "select c, b from t where c = 1 limit 1", + // Test Selection + Limit push down in double single read. + "select c, b from t where c = 1 and e = 1 and b = 1 limit 1", + // Test Order by multi columns. + "select c from t where c = 1 order by d, c", + // Test for index with length. + "select c_str from t where e_str = '1' order by d_str, c_str", + // Test PK in index single read. + "select c from t where t.c = 1 and t.a > 1 order by t.d limit 1", + // Test composed index. + // FIXME: The TopN didn't be pushed. + "select c from t where t.c = 1 and t.d = 1 order by t.a limit 1", + // Test PK in index double read. + "select * from t where t.c = 1 and t.a > 1 order by t.d limit 1", + // Test index filter condition push down. + "select * from t use index(e_d_c_str_prefix) where t.c_str = 'abcdefghijk' and t.d_str = 'd' and t.e_str = 'e'", + "select * from t use index(e_d_c_str_prefix) where t.e_str = b'1110000'", + "select * from (select * from t use index() order by b) t left join t t1 on t.a=t1.a limit 10", + // Test embedded ORDER BY which imposes on different number of columns than outer query. + "select * from ((SELECT 1 a,3 b) UNION (SELECT 2,1) ORDER BY (SELECT 2)) t order by a,b", + "select * from ((SELECT 1 a,6 b) UNION (SELECT 2,5) UNION (SELECT 2, 4) ORDER BY 1) t order by 1, 2", + "select * from (select *, NULL as xxx from t) t order by xxx", + "select lead(a, 1) over (partition by null) as c from t", + "select * from t use index(f) where f = 1 and a = 1", + "select * from t2 use index(b) where b = 1 and a = 1" + ] + }, + { + "name": "TestDAGPlanBuilderJoin", + "cases": [ + "select * from t t1 join t t2 on t1.a = t2.c_str", + "select * from t t1 join t t2 on t1.b = t2.a", + "select * from t t1 join t t2 on t1.a = t2.a join t t3 on t1.a = t3.a", + "select * from t t1 join t t2 on t1.a = t2.a join t t3 on t1.b = t3.a", + "select * from t t1 join t t2 on t1.b = t2.a order by t1.a", + "select * from t t1 join t t2 on t1.b = t2.a order by t1.a limit 1", + // Test hash join's hint. + "select /*+ TIDB_HJ(t1, t2) */ * from t t1 join t t2 on t1.b = t2.a order by t1.a limit 1", + "select * from t t1 left join t t2 on t1.b = t2.a where 1 = 1 limit 1", + "select * from t t1 join t t2 on t1.b = t2.a and t1.c = 1 and t1.d = 1 and t1.e = 1 order by t1.a limit 1", + "select * from t t1 join t t2 on t1.b = t2.b join t t3 on t1.b = t3.b", + "select * from t t1 join t t2 on t1.a = t2.a order by t1.a", + "select * from t t1 left outer join t t2 on t1.a = t2.a right outer join t t3 on t1.a = t3.a", + "select * from t t1 join t t2 on t1.a = t2.a join t t3 on t1.a = t3.a and t1.b = 1 and t3.c = 1", + "select * from t where t.c in (select b from t s where s.a = t.a)", + "select t.c in (select b from t s where s.a = t.a) from t", + // Test Single Merge Join. + // Merge Join now enforce a sort. + "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.b", + "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.a", + // Test Single Merge Join + Sort. + "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.a order by t2.a", + "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.b = t2.b order by t2.a", + // Test Single Merge Join + Sort + desc. + "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.a order by t2.a desc", + "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.b = t2.b order by t2.b desc", + // Test Multi Merge Join. + "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a", + "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.a = t2.b and t2.a = t3.b", + // Test Multi Merge Join with multi keys. + // TODO: More tests should be added. + "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.c = t2.c and t1.d = t2.d and t3.c = t1.c and t3.d = t1.d", + "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.c = t2.c and t1.d = t2.d and t3.c = t1.c and t3.d = t1.d order by t1.c", + // Test Multi Merge Join + Outer Join. + "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1 left outer join t t2 on t1.a = t2.a left outer join t t3 on t2.a = t3.a", + "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1 left outer join t t2 on t1.a = t2.a left outer join t t3 on t1.a = t3.a", + // Test Index Join + TableScan. + "select /*+ TIDB_INLJ(t1, t2) */ * from t t1, t t2 where t1.a = t2.a", + // Test Index Join + DoubleRead. + "select /*+ TIDB_INLJ(t2) */ * from t t1, t t2 where t1.a = t2.c", + // Test Index Join + SingleRead. + "select /*+ TIDB_INLJ(t2) */ t1.a , t2.a from t t1, t t2 where t1.a = t2.c", + // Test Index Join + Order by. + "select /*+ TIDB_INLJ(t1, t2) */ t1.a, t2.a from t t1, t t2 where t1.a = t2.a order by t1.c", + // Test Index Join + Order by. + "select /*+ TIDB_INLJ(t1, t2) */ t1.a, t2.a from t t1, t t2 where t1.a = t2.a order by t2.c", + // Test Index Join + TableScan + Rotate. + "select /*+ TIDB_INLJ(t1) */ t1.a , t2.a from t t1, t t2 where t1.a = t2.c", + // Test Index Join + OuterJoin + TableScan. + "select /*+ TIDB_INLJ(t1, t2) */ * from t t1 left outer join t t2 on t1.a = t2.a and t2.b < 1", + "select /*+ TIDB_INLJ(t1, t2) */ * from t t1 join t t2 on t1.d=t2.d and t2.c = 1", + // Test Index Join failed. + "select /*+ TIDB_INLJ(t1, t2) */ * from t t1 left outer join t t2 on t1.a = t2.b", + // Test Index Join failed. + "select /*+ TIDB_INLJ(t2) */ * from t t1 right outer join t t2 on t1.a = t2.b", + // Test Semi Join hint success. + "select /*+ TIDB_INLJ(t2) */ * from t t1 where t1.a in (select a from t t2)", + // Test Semi Join hint fail. + "select /*+ TIDB_INLJ(t1) */ * from t t1 where t1.a in (select a from t t2)", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.c=t2.c and t1.f=t2.f", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.a = t2.a and t1.f=t2.f", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.f=t2.f and t1.a=t2.a", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.a=t2.a and t2.a in (1, 2)", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.b=t2.c and t1.b=1 and t2.d > t1.d-10 and t2.d < t1.d+10", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.b=t2.b and t1.c=1 and t2.c=1 and t2.d > t1.d-10 and t2.d < t1.d+10", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t2.c > t1.d-10 and t2.c < t1.d+10", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.b = t2.c and t2.c=1 and t2.d=2 and t2.e=4", + "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t2.c=1 and t2.d=1 and t2.e > 10 and t2.e < 20" + ] + }, + { + "name": "TestDAGPlanBuilderSubquery", + "cases": [ + // Test join key with cast. + "select * from t where exists (select s.a from t s having sum(s.a) = t.a )", + "select * from t where exists (select s.a from t s having sum(s.a) = t.a ) order by t.a", + // FIXME: Report error by resolver. + // "select * from t where exists (select s.a from t s having s.a = t.a ) order by t.a", + "select * from t where a in (select s.a from t s) order by t.a", + // Test Nested sub query. + "select * from t where exists (select s.a from t s where s.c in (select c from t as k where k.d = s.d) having sum(s.a) = t.a )", + // Test Semi Join + Order by. + "select * from t where a in (select a from t) order by b", + // Test Apply. + "select t.c in (select count(*) from t s, t t1 where s.a = t.a and s.a = t1.a) from t", + "select (select count(*) from t s, t t1 where s.a = t.a and s.a = t1.a) from t", + "select (select count(*) from t s, t t1 where s.a = t.a and s.a = t1.a) from t order by t.a" + ] + }, + { + "name": "TestDAGPlanTopN", + "cases": [ + "select * from t t1 left join t t2 on t1.b = t2.b left join t t3 on t2.b = t3.b order by t1.a limit 1", + "select * from t t1 left join t t2 on t1.b = t2.b left join t t3 on t2.b = t3.b order by t1.b limit 1", + "select * from t t1 left join t t2 on t1.b = t2.b left join t t3 on t2.b = t3.b limit 1", + "select * from t where b = 1 and c = 1 order by c limit 1", + "select * from t where c = 1 order by c limit 1", + "select * from t order by a limit 1", + "select c from t order by c limit 1" + ] + }, + { + "name": "TestDAGPlanBuilderBasePhysicalPlan", + "cases": [ + // Test for update. + // TODO: This is not reasonable. Mysql do like this because the limit of InnoDB, should TiDB keep consistency with MySQL? + "select * from t order by b limit 1 for update", + // Test complex update. + "update t set a = 5 where b < 1 order by d limit 1", + // Test simple update. + "update t set a = 5", + // TODO: Test delete/update with join. + // Test join hint for delete and update + "delete /*+ TIDB_INLJ(t1, t2) */ t1 from t t1, t t2 where t1.c=t2.c", + "delete /*+ TIDB_SMJ(t1, t2) */ from t1 using t t1, t t2 where t1.c=t2.c", + "update /*+ TIDB_SMJ(t1, t2) */ t t1, t t2 set t1.a=1, t2.a=1 where t1.a=t2.a", + "update /*+ TIDB_HJ(t1, t2) */ t t1, t t2 set t1.a=1, t2.a=1 where t1.a=t2.a", + // Test complex delete. + "delete from t where b < 1 order by d limit 1", + // Test simple delete. + "delete from t", + // Test "USE INDEX" hint in delete statement from single table + "delete from t use index(c_d_e) where b = 1", + // Test complex insert. + "insert into t select * from t where b < 1 order by d limit 1", + // Test simple insert. + "insert into t (a, b, c, e, f, g) values(0,0,0,0,0,0)", + // Test dual. + "select 1", + "select * from t where false", + // Test show. + "show tables" + ] + }, + { + "name": "TestDAGPlanBuilderUnion", + "cases": [ + // Test simple union. + "select * from t union all select * from t", + // Test Order by + Union. + "select * from t union all (select * from t) order by a ", + // Test Limit + Union. + "select * from t union all (select * from t) limit 1", + // Test TopN + Union. + "select a from t union all (select c from t) order by a limit 1" + ] + }, + { + "name": "TestDAGPlanBuilderUnionScan", + "cases": [ + // Read table. + "select * from t", + "select * from t where b = 1", + "select * from t where a = 1", + "select * from t where a = 1 order by a", + "select * from t where a = 1 order by b", + "select * from t where a = 1 limit 1", + "select * from t where c = 1", + "select c from t where c = 1" + ] + }, + { + "name": "TestDAGPlanBuilderAgg", + "cases": [ + // Test distinct. + "select distinct b from t", + "select count(*) from (select * from t order by b) t group by b", + "select count(*), x from (select b as bbb, a + 1 as x from (select * from t order by b) t) t group by bbb", + // Test agg + table. + "select sum(a), avg(b + c) from t group by d", + "select sum(distinct a), avg(b + c) from t group by d", + // Test group by (c + d) + "select sum(e), avg(e + c) from t where c = 1 group by (c + d)", + // Test stream agg + index single. + "select sum(e), avg(e + c) from t where c = 1 group by c", + // Test hash agg + index single. + "select sum(e), avg(e + c) from t where c = 1 group by e", + // Test hash agg + index double. + "select sum(e), avg(b + c) from t where c = 1 and e = 1 group by d", + // Test stream agg + index double. + "select sum(e), avg(b + c) from t where c = 1 and b = 1", + // Test hash agg + order. + "select sum(e) as k, avg(b + c) from t where c = 1 and b = 1 and e = 1 group by d order by k", + // Test stream agg + order. + "select sum(e) as k, avg(b + c) from t where c = 1 and b = 1 and e = 1 group by c order by k", + // Test agg can't push down. + "select sum(to_base64(e)) from t where c = 1", + "select (select count(1) k from t s where s.a = t.a having k != 0) from t", + // Test stream agg with multi group by columns. + "select sum(to_base64(e)) from t group by e,d,c order by c", + "select sum(e+1) from t group by e,d,c order by c", + "select sum(to_base64(e)) from t group by e,d,c order by c,e", + "select sum(e+1) from t group by e,d,c order by c,e", + // Test stream agg + limit or sort + "select count(*) from t group by g order by g limit 10", + "select count(*) from t group by g limit 10", + "select count(*) from t group by g order by g", + "select count(*) from t group by g order by g desc limit 1", + // Test hash agg + limit or sort + "select count(*) from t group by b order by b limit 10", + "select count(*) from t group by b order by b", + "select count(*) from t group by b limit 10", + // Test merge join + stream agg + "select sum(a.g), sum(b.g) from t a join t b on a.g = b.g group by a.g", + // Test index join + stream agg + "select /*+ tidb_inlj(a,b) */ sum(a.g), sum(b.g) from t a join t b on a.g = b.g and a.g > 60 group by a.g order by a.g limit 1", + "select sum(a.g), sum(b.g) from t a join t b on a.g = b.g and a.a>5 group by a.g order by a.g limit 1", + "select sum(d) from t" + ] + }, + { + "name": "TestRefine", + "cases": [ + "select a from t where c is not null", + "select a from t where c >= 4", + "select a from t where c <= 4", + "select a from t where c = 4 and d = 5 and e = 6", + "select a from t where d = 4 and c = 5", + "select a from t where c = 4 and e < 5", + "select a from t where c = 4 and d <= 5 and d > 3", + "select a from t where d <= 5 and d > 3", + "select a from t where c between 1 and 2", + "select a from t where c not between 1 and 2", + "select a from t where c <= 5 and c >= 3 and d = 1", + "select a from t where c = 1 or c = 2 or c = 3", + "select b from t where c = 1 or c = 2 or c = 3 or c = 4 or c = 5", + "select a from t where c = 5", + "select a from t where c = 5 and b = 1", + "select a from t where not a", + "select a from t where c in (1)", + "select a from t where c in ('1')", + "select a from t where c = 1.0", + "select a from t where c in (1) and d > 3", + "select a from t where c in (1, 2, 3) and (d > 3 and d < 4 or d > 5 and d < 6)", + "select a from t where c in (1, 2, 3) and (d > 2 and d < 4 or d > 5 and d < 7)", + "select a from t where c in (1, 2, 3)", + "select a from t where c in (1, 2, 3) and d in (1,2) and e = 1", + "select a from t where d in (1, 2, 3)", + "select a from t where c not in (1)", + "select a from t use index(c_d_e) where c != 1", + // test like + "select a from t where c_str like ''", + "select a from t where c_str like 'abc'", + "select a from t where c_str not like 'abc'", + "select a from t where not (c_str like 'abc' or c_str like 'abd')", + "select a from t where c_str like '_abc'", + "select a from t where c_str like 'abc%'", + "select a from t where c_str like 'abc_'", + "select a from t where c_str like 'abc%af'", + "select a from t where c_str like 'abc\\_' escape ''", + "select a from t where c_str like 'abc\\_'", + "select a from t where c_str like 'abc\\\\_'", + "select a from t where c_str like 'abc\\_%'", + "select a from t where c_str like 'abc=_%' escape '='", + "select a from t where c_str like 'abc\\__'", + // Check that 123 is converted to string '123'. index can be used. + "select a from t where c_str like 123", + "select a from t where c = 1.9 and d > 3", + "select a from t where c < 1.1", + "select a from t where c <= 1.9", + "select a from t where c >= 1.1", + "select a from t where c > 1.9", + "select a from t where c = 123456789098765432101234", + "select a from t where c = 'hanfei'" + ] + }, + { + "name": "TestAggEliminator", + "cases": [ + // Max to Limit + Sort-Desc. + "select max(a) from t;", + // Min to Limit + Sort. + "select min(a) from t;", + // Min to Limit + Sort, and isnull() should be added. + "select min(c_str) from t;", + // Do nothing to max + firstrow. + "select max(a), b from t;", + // If max/min contains scalar function, we can still do transformation. + "select max(a+1) from t;", + // Min + Max to Limit + Sort + Join. + "select max(a), min(a) from t;", + // Min + Max with range condition. + "select max(a), min(a) from t where a > 10", + // Min + Max with unified index range condition. + "select max(d), min(d) from t where c = 1 and d > 10", + // Min + Max with multiple columns + "select max(a), max(c), min(f) from t", + // Do nothing if any column has no index. + "select max(a), max(b) from t", + // Do nothing if any column has a non-range condition. + "select max(a), max(c) from t where c > 10", + // Do nothing if the condition cannot be pushed down to range. + "select max(a), min(a) from t where a * 3 + 10 < 100", + // Do nothing to max with groupby. + "select max(a) from t group by b;", + // If inner is not a data source, we can still do transformation. + "select max(a) from (select t1.a from t t1 join t t2 on t1.a=t2.a) t" + ] + }, + { + "name": "TestUnmatchedTableInHint", + "cases": [ + "SELECT /*+ TIDB_SMJ(t3, t4) */ * from t t1, t t2 where t1.a = t2.a", + "SELECT /*+ TIDB_HJ(t3, t4) */ * from t t1, t t2 where t1.a = t2.a", + "SELECT /*+ TIDB_INLJ(t3, t4) */ * from t t1, t t2 where t1.a = t2.a", + "SELECT /*+ TIDB_SMJ(t1, t2) */ * from t t1, t t2 where t1.a = t2.a", + "SELECT /*+ TIDB_SMJ(t3, t4) */ * from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a" + ] + }, + { + "name": "TestJoinHints", + "cases": [ + "select /*+ TIDB_INLJ(t1) */ t1.a, t2.a, t3.a from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a;", + "select /*+ TIDB_INLJ(t1) */ t1.b, t2.a from t t1, t t2 where t1.b = t2.a;", + "select /*+ TIDB_INLJ(t2) */ t1.b, t2.a from t2 t1, t2 t2 where t1.b=t2.b and t2.c=-1;" + ] + }, + { + "name":"TestAggregationHints", + "cases": [ + // without Aggregation hints + {"SQL": "select count(*) from t t1, t t2 where t1.a = t2.b"}, + {"SQL": "select count(t1.a) from t t1, t t2 where t1.a = t2.a*2 group by t1.a"}, + // with Aggregation hints + {"SQL": "select /*+ HASH_AGG() */ count(*) from t t1, t t2 where t1.a = t2.b"}, + {"SQL": "select /*+ STREAM_AGG() */ count(t1.a) from t t1, t t2 where t1.a = t2.a*2 group by t1.a"}, + // test conflict warning + {"SQL": "select /*+ HASH_AGG() STREAM_AGG() */ count(*) from t t1, t t2 where t1.a = t2.b"}, + {"SQL": "select /*+ STREAM_AGG() */ distinct a from t"}, + // additional test + {"SQL": "select /*+ HASH_AGG() */ t1.a from t t1 where t1.a < any(select t2.b from t t2)"}, + {"SQL": "select /*+ hash_agg() */ t1.a from t t1 where t1.a != any(select t2.b from t t2)"}, + {"SQL": "select /*+ hash_agg() */ t1.a from t t1 where t1.a = all(select t2.b from t t2)"}, + {"SQL": "select /*+ STREAM_AGG() */ sum(t1.a) from t t1 join t t2 on t1.b = t2.b group by t1.b", "AggPushDown": true}, + {"SQL": "select /*+ STREAM_AGG() */ e, sum(b) from t group by e"} + ] + }, + { + "name": "TestQueryBlockHint", + "cases": [ + "select /*+ SM_JOIN(@sel_1 t1), INL_JOIN(@sel_2 t3) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ SM_JOIN(@sel_1 t1), INL_JOIN(@qb t3) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ HASH_JOIN(@sel_1 t1), SM_JOIN(@sel_2 t2) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ HASH_JOIN(@sel_1 t1), SM_JOIN(@qb t2) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ INL_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t2) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ INL_JOIN(@sel_1 t1), HASH_JOIN(@qb t2) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "select /*+ HASH_AGG(@sel_1), STREAM_AGG(@sel_2) */ count(*) from t t1 where t1.a < (select count(*) from t t2 where t1.a > t2.a)", + "select /*+ STREAM_AGG(@sel_1), HASH_AGG(@qb) */ count(*) from t t1 where t1.a < (select /*+ QB_NAME(qb) */ count(*) from t t2 where t1.a > t2.a)", + "select /*+ HASH_AGG(@sel_2) */ a, (select count(*) from t t1 where t1.b > t.a) from t where b > (select b from t t2 where t2.b = t.a limit 1)", + "select /*+ HASH_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t1) */ t1.b, t2.a, t2.aa from t t1, (select t1.a as a, t2.a as aa from t t1, t t2) t2 where t1.a = t2.aa;" + ] + }, + { + "name": "TestIndexJoinUnionScan", + "cases": [ + // Test Index Join + UnionScan + TableScan. + "select /*+ TIDB_INLJ(t2) */ * from t t1, t t2 where t1.a = t2.a", + // Test Index Join + UnionScan + DoubleRead. + "select /*+ TIDB_INLJ(t1, t2) */ * from t t1, t t2 where t1.a = t2.c", + // Test Index Join + UnionScan + IndexScan. + "select /*+ TIDB_INLJ(t1, t2) */ t1.a , t2.c from t t1, t t2 where t1.a = t2.c" + ] + }, + { + "name": "TestSemiJoinToInner", + "cases": [ + "select t1.a, (select count(t2.a) from t t2 where t2.g in (select t3.d from t t3 where t3.c = t1.a)) as agg_col from t t1;" + ] + }, + { + "name": "TestSimplifyOuterJoinWithCast", + "cases": [ + "select * from t t1 left join t t2 on t1.a = t2.a where cast(t1.c_str as float) = '2.3'" + ] + } +] diff --git a/planner/core/testdata/plan_suite_out.json b/planner/core/testdata/plan_suite_out.json new file mode 100644 index 0000000000000..420dcc7b9253c --- /dev/null +++ b/planner/core/testdata/plan_suite_out.json @@ -0,0 +1,1254 @@ +[ + { + "Name": "TestHintScope", + "Cases": [ + { + "SQL": "select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(t3) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)->Sort}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "IndexMergeJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#13,Column#1)->Projection" + }, + { + "SQL": "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ SM_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "IndexMergeJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#13,Column#1)->Projection" + }, + { + "SQL": "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ SM_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "RightHashJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "RightHashJoin{TableReader(Table(t))->IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#27,Column#13)}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "IndexMergeJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#13,Column#1)->Projection" + }, + { + "SQL": "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Best": "RightHashJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ STREAM_AGG() */ s, count(s) from (select /*+ HASH_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->Projection->HashAgg->Sort->StreamAgg->Projection" + }, + { + "SQL": "select /*+ HASH_AGG() */ s, count(s) from (select /*+ STREAM_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->Sort->Projection->StreamAgg->HashAgg->Projection" + }, + { + "SQL": "select /*+ HASH_AGG() */ s, count(s) from (select sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->Projection->HashAgg->HashAgg->Projection" + }, + { + "SQL": "select /*+ STREAM_AGG() */ s, count(s) from (select sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->Projection->HashAgg->Sort->StreamAgg->Projection" + } + ] + }, + { + "Name": "TestIndexHint", + "Cases": [ + { + "SQL": "select /*+ USE_INDEX(t, c_d_e) */ * from t", + "Best": "IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` `c_d_e`)" + }, + { + "SQL": "select /*+ IGNORE_INDEX(t, c_d_e) */ c from t order by c", + "Best": "TableReader(Table(t))->Sort", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "select /*+ USE_INDEX(t, c_d_e) */ * from t t1", + "Best": "TableReader(Table(t))", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t1` )" + }, + { + "SQL": "select /*+ IGNORE_INDEX(t, c_d_e) */ t1.c from t t1 order by t1.c", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]])", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t1` `c_d_e`)" + }, + { + "SQL": "select /*+ USE_INDEX(t1, c_d_e) */ * from t t1", + "Best": "IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t1` `c_d_e`)" + }, + { + "SQL": "select /*+ IGNORE_INDEX(t1, c_d_e) */ t1.c from t t1 order by t1.c", + "Best": "TableReader(Table(t))->Sort", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t1` )" + }, + { + "SQL": "select /*+ USE_INDEX(t1, c_d_e), USE_INDEX(t2, f) */ * from t t1, t t2 where t1.a = t2.b", + "Best": "LeftHashJoin{IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))->IndexLookUp(Index(t.f)[[NULL,+inf]], Table(t))}(Column#1,Column#14)", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t1` `c_d_e`), USE_INDEX(@`sel_1` `t2` `f`), HASH_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ IGNORE_INDEX(t1, c_d_e), IGNORE_INDEX(t2, f), HASH_JOIN(t1) */ * from t t1, t t2 where t1.a = t2.b", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#14)", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_1` `t2` ), HASH_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ USE_INDEX(t, c_d_e, f, g) */ * from t order by f", + "Best": "IndexLookUp(Index(t.f)[[NULL,+inf]], Table(t))", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` `f`)" + }, + { + "SQL": "select /*+ USE_INDEX(t) */ f from t where f > 10", + "Best": "TableReader(Table(t)->Sel([gt(Column#9, 10)]))", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "select /*+ USE_INDEX(t, no_such_index) */ * from t", + "Best": "TableReader(Table(t))", + "HasWarn": true, + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "select /*+ IGNORE_INDEX(t, no_such_index) */ * from t", + "Best": "TableReader(Table(t))", + "HasWarn": true, + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "select /*+ USE_INDEX(t, c_d_e), IGNORE_INDEX(t, f) */ c from t order by c", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]])", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` `c_d_e`)" + }, + { + "SQL": "select /*+ USE_INDEX(t, f), IGNORE_INDEX(t, f) */ c from t order by c", + "Best": "TableReader(Table(t))->Sort", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "select /*+ USE_INDEX(t, c_d_e), IGNORE_INDEX(t, c_d_e) */ c from t order by c", + "Best": "TableReader(Table(t))->Sort", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "select /*+ USE_INDEX(t, c_d_e, f), IGNORE_INDEX(t, c_d_e) */ c from t order by c", + "Best": "IndexLookUp(Index(t.f)[[NULL,+inf]], Table(t))->Sort", + "HasWarn": false, + "Hints": "USE_INDEX(@`sel_1` `t` `f`)" + } + ] + }, + { + "Name": "TestDAGPlanBuilderSimpleCase", + "Cases": [ + { + "SQL": "select * from t t1 use index(c_d_e)", + "Best": "IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))" + }, + { + "SQL": "select f from t use index() where f = 1", + "Best": "TableReader(Table(t)->Sel([eq(Column#9, 1)]))" + }, + { + "SQL": "select a from t where a between 1 and 2 order by c", + "Best": "TableReader(Table(t))->Sort->Projection" + }, + { + "SQL": "select * from t where (t.c > 0 and t.c < 2) or (t.c > 4 and t.c < 6) or (t.c > 8 and t.c < 10) or (t.c > 12 and t.c < 14) or (t.c > 16 and t.c < 18)", + "Best": "IndexLookUp(Index(t.c_d_e)[(0,2) (4,6) (8,10) (12,14) (16,18)], Table(t))" + }, + { + "SQL": "select * from t where (t.c > 0 and t.c < 1) or (t.c > 2 and t.c < 3) or (t.c > 4 and t.c < 5) or (t.c > 6 and t.c < 7) or (t.c > 9 and t.c < 10)", + "Best": "Dual" + }, + { + "SQL": "select * from t where t.c = 1 and t.e = 1 order by t.b limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)]), Table(t))->TopN([Column#2],0,1)" + }, + { + "SQL": "select * from t where t.e_str is null", + "Best": "IndexLookUp(Index(t.e_d_c_str_prefix)[[NULL,NULL]], Table(t))" + }, + { + "SQL": "select * from t where t.c is null", + "Best": "Dual" + }, + { + "SQL": "select * from t where t.c = 1 and t.e = 1 order by t.e limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)]), Table(t))->TopN([Column#5],0,1)" + }, + { + "SQL": "select * from t where t.c = 1 and t.e = 1 order by t.d limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)])->Limit, Table(t))" + }, + { + "SQL": "select c from t where t.c = 1 and t.e = 1 order by t.d limit 1", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)])->Limit)->Limit->Projection" + }, + { + "SQL": "select c from t order by t.a limit 1", + "Best": "TableReader(Table(t)->Limit)->Limit->Projection" + }, + { + "SQL": "select c from t order by t.a + t.b limit 1", + "Best": "TableReader(Table(t)->TopN([plus(Column#1, Column#2)],0,1))->Projection->TopN([Column#17],0,1)->Projection->Projection" + }, + { + "SQL": "select c from t limit 1", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->Limit)->Limit" + }, + { + "SQL": "select c from t where c = 1 limit 1", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]]->Limit)->Limit" + }, + { + "SQL": "select c from t where c = 1", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])" + }, + { + "SQL": "select c from t order by c", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]])" + }, + { + "SQL": "select c from t where c = 1 order by e", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])->Sort->Projection" + }, + { + "SQL": "select c, b from t where c = 1 limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Limit, Table(t))->Projection" + }, + { + "SQL": "select c, b from t where c = 1 and e = 1 and b = 1 limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)]), Table(t)->Sel([eq(Column#2, 1)])->Limit)->Limit->Projection" + }, + { + "SQL": "select c from t where c = 1 order by d, c", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])->Sort->Projection" + }, + { + "SQL": "select c_str from t where e_str = '1' order by d_str, c_str", + "Best": "IndexLookUp(Index(t.e_d_c_str_prefix)[[\"1\",\"1\"]], Table(t))->Sort->Projection" + }, + { + "SQL": "select c from t where t.c = 1 and t.a > 1 order by t.d limit 1", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]]->Sel([gt(Column#1, 1)])->Limit)->Limit->Projection" + }, + { + "SQL": "select c from t where t.c = 1 and t.d = 1 order by t.a limit 1", + "Best": "IndexReader(Index(t.c_d_e)[[1 1,1 1]])->TopN([Column#1],0,1)->Projection" + }, + { + "SQL": "select * from t where t.c = 1 and t.a > 1 order by t.d limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([gt(Column#1, 1)])->Limit, Table(t))" + }, + { + "SQL": "select * from t use index(e_d_c_str_prefix) where t.c_str = 'abcdefghijk' and t.d_str = 'd' and t.e_str = 'e'", + "Best": "IndexLookUp(Index(t.e_d_c_str_prefix)[[\"e\" \"d\" \"abcdefghij\",\"e\" \"d\" \"abcdefghij\"]], Table(t)->Sel([eq(Column#6, abcdefghijk)]))" + }, + { + "SQL": "select * from t use index(e_d_c_str_prefix) where t.e_str = b'1110000'", + "Best": "IndexLookUp(Index(t.e_d_c_str_prefix)[[\"p\",\"p\"]], Table(t))" + }, + { + "SQL": "select * from (select * from t use index() order by b) t left join t t1 on t.a=t1.a limit 10", + "Best": "IndexMergeJoin{TableReader(Table(t)->TopN([Column#2],0,10))->TopN([Column#2],0,10)->TableReader(Table(t))}(Column#1,Column#25)->Limit" + }, + { + "SQL": "select * from ((SELECT 1 a,3 b) UNION (SELECT 2,1) ORDER BY (SELECT 2)) t order by a,b", + "Best": "UnionAll{Dual->Projection->Dual->Projection}->HashAgg->Sort" + }, + { + "SQL": "select * from ((SELECT 1 a,6 b) UNION (SELECT 2,5) UNION (SELECT 2, 4) ORDER BY 1) t order by 1, 2", + "Best": "UnionAll{Dual->Projection->Dual->Projection->Dual->Projection}->HashAgg->Sort->Sort" + }, + { + "SQL": "select * from (select *, NULL as xxx from t) t order by xxx", + "Best": "TableReader(Table(t))->Projection" + }, + { + "SQL": "select lead(a, 1) over (partition by null) as c from t", + "Best": "IndexReader(Index(t.f)[[NULL,+inf]])->Window(lead(Column#1, 1) over())->Projection" + }, + { + "SQL": "select * from t use index(f) where f = 1 and a = 1", + "Best": "IndexLookUp(Index(t.f)[[1,1]]->Sel([eq(Column#1, 1)]), Table(t))" + }, + { + "SQL": "select * from t2 use index(b) where b = 1 and a = 1", + "Best": "IndexLookUp(Index(t2.b)[[1,1]]->Sel([eq(Column#1, 1)]), Table(t2))" + } + ] + }, + { + "Name": "TestDAGPlanBuilderJoin", + "Cases": [ + { + "SQL": "select * from t t1 join t t2 on t1.a = t2.c_str", + "Best": "LeftHashJoin{TableReader(Table(t))->Projection->TableReader(Table(t))->Projection}(Column#49,Column#50)->Projection" + }, + { + "SQL": "select * from t t1 join t t2 on t1.b = t2.a", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#2,Column#13)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.a = t2.a join t t3 on t1.a = t3.a", + "Best": "LeftHashJoin{MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->TableReader(Table(t))}(Column#1,Column#25)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.a = t2.a join t t3 on t1.b = t3.a", + "Best": "LeftHashJoin{MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->TableReader(Table(t))}(Column#2,Column#25)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.b = t2.a order by t1.a", + "Best": "IndexJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#2,Column#13)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.b = t2.a order by t1.a limit 1", + "Best": "IndexJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#2,Column#13)->Limit" + }, + { + "SQL": "select /*+ TIDB_HJ(t1, t2) */ * from t t1 join t t2 on t1.b = t2.a order by t1.a limit 1", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#2,Column#13)->TopN([Column#1],0,1)" + }, + { + "SQL": "select * from t t1 left join t t2 on t1.b = t2.a where 1 = 1 limit 1", + "Best": "IndexMergeJoin{TableReader(Table(t)->Limit)->Limit->TableReader(Table(t))}(Column#2,Column#13)->Limit" + }, + { + "SQL": "select * from t t1 join t t2 on t1.b = t2.a and t1.c = 1 and t1.d = 1 and t1.e = 1 order by t1.a limit 1", + "Best": "IndexMergeJoin{IndexLookUp(Index(t.c_d_e)[[1 1 1,1 1 1]], Table(t))->TableReader(Table(t))}(Column#2,Column#13)->TopN([Column#1],0,1)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.b = t2.b join t t3 on t1.b = t3.b", + "Best": "LeftHashJoin{LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#2,Column#14)->TableReader(Table(t))}(Column#2,Column#26)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.a = t2.a order by t1.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select * from t t1 left outer join t t2 on t1.a = t2.a right outer join t t3 on t1.a = t3.a", + "Best": "MergeRightOuterJoin{MergeLeftOuterJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->TableReader(Table(t))}(Column#1,Column#25)" + }, + { + "SQL": "select * from t t1 join t t2 on t1.a = t2.a join t t3 on t1.a = t3.a and t1.b = 1 and t3.c = 1", + "Best": "IndexMergeJoin{IndexMergeJoin{TableReader(Table(t)->Sel([eq(Column#2, 1)]))->IndexLookUp(Index(t.c_d_e)[[1,1]], Table(t))}(Column#25,Column#1)->TableReader(Table(t))}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select * from t where t.c in (select b from t s where s.a = t.a)", + "Best": "MergeSemiJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select t.c in (select b from t s where s.a = t.a) from t", + "Best": "LeftHashJoin{IndexReader(Index(t.c_d_e)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#13)(Column#3,Column#14)->Projection" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.b", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))->Sort}(Column#1,Column#14)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.a order by t2.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.b = t2.b order by t2.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->Sort->TableReader(Table(t))->Sort}(Column#2,Column#14)->Sort" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.a = t2.a order by t2.a desc", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2)*/ * from t t1, t t2 where t1.b = t2.b order by t2.b desc", + "Best": "MergeInnerJoin{TableReader(Table(t))->Sort->TableReader(Table(t))->Sort}(Column#2,Column#14)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a", + "Best": "MergeInnerJoin{MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->TableReader(Table(t))}(Column#13,Column#25)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.a = t2.b and t2.a = t3.b", + "Best": "MergeInnerJoin{MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))->Sort}(Column#1,Column#14)->Sort->TableReader(Table(t))->Sort}(Column#13,Column#26)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.c = t2.c and t1.d = t2.d and t3.c = t1.c and t3.d = t1.d", + "Best": "MergeInnerJoin{MergeInnerJoin{IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#15)(Column#4,Column#16)->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#27)(Column#4,Column#28)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1, t t2, t t3 where t1.c = t2.c and t1.d = t2.d and t3.c = t1.c and t3.d = t1.d order by t1.c", + "Best": "MergeInnerJoin{MergeInnerJoin{IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#15)(Column#4,Column#16)->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#27)(Column#4,Column#28)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1 left outer join t t2 on t1.a = t2.a left outer join t t3 on t2.a = t3.a", + "Best": "MergeLeftOuterJoin{MergeLeftOuterJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->TableReader(Table(t))}(Column#13,Column#25)" + }, + { + "SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1 left outer join t t2 on t1.a = t2.a left outer join t t3 on t1.a = t3.a", + "Best": "MergeLeftOuterJoin{MergeLeftOuterJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->TableReader(Table(t))}(Column#1,Column#25)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ * from t t1, t t2 where t1.a = t2.a", + "Best": "IndexMergeJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1, t t2 where t1.a = t2.c", + "Best": "IndexMergeJoin{TableReader(Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#1,Column#15)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ t1.a , t2.a from t t1, t t2 where t1.a = t2.c", + "Best": "IndexMergeJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#1,Column#15)->Projection" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ t1.a, t2.a from t t1, t t2 where t1.a = t2.a order by t1.c", + "Best": "IndexJoin{IndexReader(Index(t.c_d_e)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ t1.a, t2.a from t t1, t t2 where t1.a = t2.a order by t2.c", + "Best": "IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#1)->Projection" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1) */ t1.a , t2.a from t t1, t t2 where t1.a = t2.c", + "Best": "IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#15,Column#1)->Projection" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ * from t t1 left outer join t t2 on t1.a = t2.a and t2.b < 1", + "Best": "IndexMergeJoin{TableReader(Table(t))->TableReader(Table(t)->Sel([lt(Column#14, 1)]))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ * from t t1 join t t2 on t1.d=t2.d and t2.c = 1", + "Best": "IndexMergeJoin{TableReader(Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#4,Column#16)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ * from t t1 left outer join t t2 on t1.a = t2.b", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#14)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 right outer join t t2 on t1.a = t2.b", + "Best": "RightHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#14)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 where t1.a in (select a from t t2)", + "Best": "LeftHashJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1) */ * from t t1 where t1.a in (select a from t t2)", + "Best": "IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#13,Column#1)->Projection" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.c=t2.c and t1.f=t2.f", + "Best": "IndexMergeJoin{TableReader(Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#15)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.a = t2.a and t1.f=t2.f", + "Best": "IndexMergeJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.f=t2.f and t1.a=t2.a", + "Best": "IndexMergeJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.a=t2.a and t2.a in (1, 2)", + "Best": "IndexMergeJoin{TableReader(Table(t))->TableReader(Table(t)->Sel([in(Column#13, 1, 2)]))}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.b=t2.c and t1.b=1 and t2.d > t1.d-10 and t2.d < t1.d+10", + "Best": "IndexHashJoin{TableReader(Table(t)->Sel([eq(Column#2, 1)]))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.b=t2.b and t1.c=1 and t2.c=1 and t2.d > t1.d-10 and t2.d < t1.d+10", + "Best": "LeftHashJoin{IndexLookUp(Index(t.c_d_e)[[1,1]], Table(t))->IndexLookUp(Index(t.c_d_e)[[1,1]], Table(t))}(Column#2,Column#14)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t2.c > t1.d-10 and t2.c < t1.d+10", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t1.b = t2.c and t2.c=1 and t2.d=2 and t2.e=4", + "Best": "LeftHashJoin{TableReader(Table(t)->Sel([eq(Column#2, 1)]))->IndexLookUp(Index(t.c_d_e)[[1 2 4,1 2 4]], Table(t))}" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1 join t t2 where t2.c=1 and t2.d=1 and t2.e > 10 and t2.e < 20", + "Best": "LeftHashJoin{TableReader(Table(t))->IndexLookUp(Index(t.c_d_e)[(1 1 10,1 1 20)], Table(t))}" + } + ] + }, + { + "Name": "TestDAGPlanBuilderSubquery", + "Cases": [ + { + "SQL": "select * from t where exists (select s.a from t s having sum(s.a) = t.a )", + "Best": "LeftHashJoin{TableReader(Table(t))->Projection->IndexReader(Index(t.f)[[NULL,+inf]]->StreamAgg)->StreamAgg}(Column#41,Column#25)->Projection" + }, + { + "SQL": "select * from t where exists (select s.a from t s having sum(s.a) = t.a ) order by t.a", + "Best": "LeftHashJoin{TableReader(Table(t))->Projection->IndexReader(Index(t.f)[[NULL,+inf]]->StreamAgg)->StreamAgg}(Column#41,Column#25)->Projection->Sort" + }, + { + "SQL": "select * from t where a in (select s.a from t s) order by t.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select * from t where exists (select s.a from t s where s.c in (select c from t as k where k.d = s.d) having sum(s.a) = t.a )", + "Best": "LeftHashJoin{TableReader(Table(t))->Projection->MergeSemiJoin{IndexReader(Index(t.c_d_e)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#15,Column#27)(Column#16,Column#28)->Projection->StreamAgg}(Column#54,Column#38)->Projection" + }, + { + "SQL": "select * from t where a in (select a from t) order by b", + "Best": "LeftHashJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#1,Column#13)->Projection->Sort" + }, + { + "SQL": "select t.c in (select count(*) from t s, t t1 where s.a = t.a and s.a = t1.a) from t", + "Best": "Apply{IndexReader(Index(t.c_d_e)[[NULL,+inf]])->MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#13,Column#25)->StreamAgg}->Projection" + }, + { + "SQL": "select (select count(*) from t s, t t1 where s.a = t.a and s.a = t1.a) from t", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#13,Column#25)->HashAgg}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select (select count(*) from t s, t t1 where s.a = t.a and s.a = t1.a) from t order by t.a", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#13,Column#25)->HashAgg}(Column#1,Column#13)->Projection->Sort->Projection" + } + ] + }, + { + "Name": "TestDAGPlanTopN", + "Cases": [ + { + "SQL": "select * from t t1 left join t t2 on t1.b = t2.b left join t t3 on t2.b = t3.b order by t1.a limit 1", + "Best": "LeftHashJoin{LeftHashJoin{TableReader(Table(t)->Limit)->Limit->TableReader(Table(t))}(Column#2,Column#14)->TopN([Column#1],0,1)->TableReader(Table(t))}(Column#14,Column#26)->TopN([Column#1],0,1)" + }, + { + "SQL": "select * from t t1 left join t t2 on t1.b = t2.b left join t t3 on t2.b = t3.b order by t1.b limit 1", + "Best": "LeftHashJoin{LeftHashJoin{TableReader(Table(t)->TopN([Column#2],0,1))->TopN([Column#2],0,1)->TableReader(Table(t))}(Column#2,Column#14)->TopN([Column#2],0,1)->TableReader(Table(t))}(Column#14,Column#26)->TopN([Column#2],0,1)" + }, + { + "SQL": "select * from t t1 left join t t2 on t1.b = t2.b left join t t3 on t2.b = t3.b limit 1", + "Best": "LeftHashJoin{LeftHashJoin{TableReader(Table(t)->Limit)->Limit->TableReader(Table(t))}(Column#2,Column#14)->Limit->TableReader(Table(t))}(Column#14,Column#26)->Limit" + }, + { + "SQL": "select * from t where b = 1 and c = 1 order by c limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]], Table(t)->Sel([eq(Column#2, 1)]))->Limit" + }, + { + "SQL": "select * from t where c = 1 order by c limit 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Limit, Table(t))" + }, + { + "SQL": "select * from t order by a limit 1", + "Best": "TableReader(Table(t)->Limit)->Limit" + }, + { + "SQL": "select c from t order by c limit 1", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->Limit)->Limit" + } + ] + }, + { + "Name": "TestDAGPlanBuilderBasePhysicalPlan", + "Cases": [ + { + "SQL": "select * from t order by b limit 1 for update", + "Best": "TableReader(Table(t))->Lock->TopN([Column#2],0,1)", + "Hints": "USE_INDEX(@`sel_1` `t` )" + }, + { + "SQL": "update t set a = 5 where b < 1 order by d limit 1", + "Best": "TableReader(Table(t)->Sel([lt(Column#2, 1)])->TopN([Column#4],0,1))->TopN([Column#4],0,1)->Update", + "Hints": "USE_INDEX(@`upd_1` `t` )" + }, + { + "SQL": "update t set a = 5", + "Best": "TableReader(Table(t))->Update", + "Hints": "USE_INDEX(@`upd_1` `t` )" + }, + { + "SQL": "delete /*+ TIDB_INLJ(t1, t2) */ t1 from t t1, t t2 where t1.c=t2.c", + "Best": "IndexMergeJoin{TableReader(Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#15)->Delete", + "Hints": "USE_INDEX(@`del_1` `t1` ), USE_INDEX(@`del_1` `t2` `c_d_e`), INL_JOIN(@`del_1` `t2`)" + }, + { + "SQL": "delete /*+ TIDB_SMJ(t1, t2) */ from t1 using t t1, t t2 where t1.c=t2.c", + "Best": "MergeInnerJoin{IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))->IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))}(Column#3,Column#15)->Delete", + "Hints": "USE_INDEX(@`del_1` `t1` `c_d_e`), USE_INDEX(@`del_1` `t2` `c_d_e`), SM_JOIN(@`del_1` `t1`)" + }, + { + "SQL": "update /*+ TIDB_SMJ(t1, t2) */ t t1, t t2 set t1.a=1, t2.a=1 where t1.a=t2.a", + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->Update", + "Hints": "USE_INDEX(@`upd_1` `t1` ), USE_INDEX(@`upd_1` `t2` ), SM_JOIN(@`upd_1` `t1`)" + }, + { + "SQL": "update /*+ TIDB_HJ(t1, t2) */ t t1, t t2 set t1.a=1, t2.a=1 where t1.a=t2.a", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->Update", + "Hints": "USE_INDEX(@`upd_1` `t1` ), USE_INDEX(@`upd_1` `t2` ), HASH_JOIN(@`upd_1` `t1`)" + }, + { + "SQL": "delete from t where b < 1 order by d limit 1", + "Best": "TableReader(Table(t)->Sel([lt(Column#2, 1)])->TopN([Column#4],0,1))->TopN([Column#4],0,1)->Delete", + "Hints": "USE_INDEX(@`del_1` `t` )" + }, + { + "SQL": "delete from t", + "Best": "TableReader(Table(t))->Delete", + "Hints": "USE_INDEX(@`del_1` `t` )" + }, + { + "SQL": "delete from t use index(c_d_e) where b = 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t)->Sel([eq(Column#2, 1)]))->Delete", + "Hints": "USE_INDEX(@`del_1` `t` `c_d_e`)" + }, + { + "SQL": "insert into t select * from t where b < 1 order by d limit 1", + "Best": "TableReader(Table(t)->Sel([lt(Column#14, 1)])->TopN([Column#16],0,1))->TopN([Column#16],0,1)->Insert", + "Hints": "" + }, + { + "SQL": "insert into t (a, b, c, e, f, g) values(0,0,0,0,0,0)", + "Best": "Insert", + "Hints": "" + }, + { + "SQL": "select 1", + "Best": "Dual->Projection", + "Hints": "" + }, + { + "SQL": "select * from t where false", + "Best": "Dual", + "Hints": "" + }, + { + "SQL": "show tables", + "Best": "Show", + "Hints": "" + } + ] + }, + { + "Name": "TestDAGPlanBuilderUnion", + "Cases": [ + { + "SQL": "select * from t union all select * from t", + "Best": "UnionAll{TableReader(Table(t))->TableReader(Table(t))}" + }, + { + "SQL": "select * from t union all (select * from t) order by a ", + "Best": "UnionAll{TableReader(Table(t))->TableReader(Table(t))}->Sort" + }, + { + "SQL": "select * from t union all (select * from t) limit 1", + "Best": "UnionAll{TableReader(Table(t)->Limit)->Limit->TableReader(Table(t)->Limit)->Limit}->Limit" + }, + { + "SQL": "select a from t union all (select c from t) order by a limit 1", + "Best": "UnionAll{TableReader(Table(t)->Limit)->Limit->IndexReader(Index(t.c_d_e)[[NULL,+inf]]->Limit)->Limit}->TopN([Column#27],0,1)" + } + ] + }, + { + "Name": "TestDAGPlanBuilderUnionScan", + "Cases": null + }, + { + "Name": "TestDAGPlanBuilderAgg", + "Cases": [ + { + "SQL": "select distinct b from t", + "Best": "TableReader(Table(t))->HashAgg" + }, + { + "SQL": "select count(*) from (select * from t order by b) t group by b", + "Best": "TableReader(Table(t))->Sort->StreamAgg" + }, + { + "SQL": "select count(*), x from (select b as bbb, a + 1 as x from (select * from t order by b) t) t group by bbb", + "Best": "TableReader(Table(t))->Sort->Projection->StreamAgg" + }, + { + "SQL": "select sum(a), avg(b + c) from t group by d", + "Best": "TableReader(Table(t)->HashAgg)->HashAgg" + }, + { + "SQL": "select sum(distinct a), avg(b + c) from t group by d", + "Best": "TableReader(Table(t))->Projection->HashAgg" + }, + { + "SQL": "select sum(e), avg(e + c) from t where c = 1 group by (c + d)", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]]->HashAgg)->HashAgg" + }, + { + "SQL": "select sum(e), avg(e + c) from t where c = 1 group by c", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]]->StreamAgg)->StreamAgg" + }, + { + "SQL": "select sum(e), avg(e + c) from t where c = 1 group by e", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]]->HashAgg)->HashAgg" + }, + { + "SQL": "select sum(e), avg(b + c) from t where c = 1 and e = 1 group by d", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)]), Table(t))->Projection->HashAgg" + }, + { + "SQL": "select sum(e), avg(b + c) from t where c = 1 and b = 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]], Table(t)->Sel([eq(Column#2, 1)]))->Projection->StreamAgg" + }, + { + "SQL": "select sum(e) as k, avg(b + c) from t where c = 1 and b = 1 and e = 1 group by d order by k", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)]), Table(t)->Sel([eq(Column#2, 1)]))->Projection->Projection->StreamAgg->Sort" + }, + { + "SQL": "select sum(e) as k, avg(b + c) from t where c = 1 and b = 1 and e = 1 group by c order by k", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,1]]->Sel([eq(Column#5, 1)]), Table(t)->Sel([eq(Column#2, 1)]))->Projection->Projection->StreamAgg->Sort" + }, + { + "SQL": "select sum(to_base64(e)) from t where c = 1", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])->Projection->StreamAgg" + }, + { + "SQL": "select (select count(1) k from t s where s.a = t.a having k != 0) from t", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]]->Sel([1]))->Projection}(Column#1,Column#13)->Projection" + }, + { + "SQL": "select sum(to_base64(e)) from t group by e,d,c order by c", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]])->Projection->StreamAgg->Projection" + }, + { + "SQL": "select sum(e+1) from t group by e,d,c order by c", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->StreamAgg)->StreamAgg->Projection" + }, + { + "SQL": "select sum(to_base64(e)) from t group by e,d,c order by c,e", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]])->Projection->StreamAgg->Sort->Projection" + }, + { + "SQL": "select sum(e+1) from t group by e,d,c order by c,e", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->StreamAgg)->StreamAgg->Sort->Projection" + }, + { + "SQL": "select count(*) from t group by g order by g limit 10", + "Best": "IndexReader(Index(t.g)[[NULL,+inf]]->StreamAgg)->StreamAgg->Limit->Projection" + }, + { + "SQL": "select count(*) from t group by g limit 10", + "Best": "IndexReader(Index(t.g)[[NULL,+inf]]->StreamAgg)->StreamAgg->Limit" + }, + { + "SQL": "select count(*) from t group by g order by g", + "Best": "IndexReader(Index(t.g)[[NULL,+inf]]->StreamAgg)->StreamAgg->Projection" + }, + { + "SQL": "select count(*) from t group by g order by g desc limit 1", + "Best": "IndexReader(Index(t.g)[[NULL,+inf]]->StreamAgg)->StreamAgg->Limit->Projection" + }, + { + "SQL": "select count(*) from t group by b order by b limit 10", + "Best": "TableReader(Table(t)->HashAgg)->HashAgg->TopN([Column#2],0,10)->Projection" + }, + { + "SQL": "select count(*) from t group by b order by b", + "Best": "TableReader(Table(t)->HashAgg)->HashAgg->Sort->Projection" + }, + { + "SQL": "select count(*) from t group by b limit 10", + "Best": "TableReader(Table(t)->HashAgg)->HashAgg->Limit" + }, + { + "SQL": "select sum(a.g), sum(b.g) from t a join t b on a.g = b.g group by a.g", + "Best": "MergeInnerJoin{IndexReader(Index(t.g)[[NULL,+inf]])->IndexReader(Index(t.g)[[NULL,+inf]])}(Column#10,Column#22)->Projection->StreamAgg" + }, + { + "SQL": "select /*+ tidb_inlj(a,b) */ sum(a.g), sum(b.g) from t a join t b on a.g = b.g and a.g > 60 group by a.g order by a.g limit 1", + "Best": "IndexMergeJoin{IndexReader(Index(t.g)[(60,+inf]])->IndexReader(Index(t.g)[[NULL,+inf]]->Sel([gt(Column#22, 60)]))}(Column#10,Column#22)->Projection->StreamAgg->Limit->Projection" + }, + { + "SQL": "select sum(a.g), sum(b.g) from t a join t b on a.g = b.g and a.a>5 group by a.g order by a.g limit 1", + "Best": "MergeInnerJoin{IndexReader(Index(t.g)[[NULL,+inf]]->Sel([gt(Column#1, 5)]))->IndexReader(Index(t.g)[[NULL,+inf]])}(Column#10,Column#22)->Projection->StreamAgg->Limit->Projection" + }, + { + "SQL": "select sum(d) from t", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->StreamAgg)->StreamAgg" + } + ] + }, + { + "Name": "TestRefine", + "Cases": [ + { + "SQL": "select a from t where c is not null", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,+inf]])->Projection" + }, + { + "SQL": "select a from t where c >= 4", + "Best": "IndexReader(Index(t.c_d_e)[[4,+inf]])->Projection" + }, + { + "SQL": "select a from t where c <= 4", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,4]])->Projection" + }, + { + "SQL": "select a from t where c = 4 and d = 5 and e = 6", + "Best": "IndexReader(Index(t.c_d_e)[[4 5 6,4 5 6]])->Projection" + }, + { + "SQL": "select a from t where d = 4 and c = 5", + "Best": "IndexReader(Index(t.c_d_e)[[5 4,5 4]])->Projection" + }, + { + "SQL": "select a from t where c = 4 and e < 5", + "Best": "IndexReader(Index(t.c_d_e)[[4,4]]->Sel([lt(Column#5, 5)]))->Projection" + }, + { + "SQL": "select a from t where c = 4 and d <= 5 and d > 3", + "Best": "IndexReader(Index(t.c_d_e)[(4 3,4 5]])->Projection" + }, + { + "SQL": "select a from t where d <= 5 and d > 3", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->Sel([le(Column#4, 5) gt(Column#4, 3)]))->Projection" + }, + { + "SQL": "select a from t where c between 1 and 2", + "Best": "IndexReader(Index(t.c_d_e)[[1,2]])->Projection" + }, + { + "SQL": "select a from t where c not between 1 and 2", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,1) (2,+inf]])->Projection" + }, + { + "SQL": "select a from t where c <= 5 and c >= 3 and d = 1", + "Best": "IndexReader(Index(t.c_d_e)[[3,5]]->Sel([eq(Column#4, 1)]))->Projection" + }, + { + "SQL": "select a from t where c = 1 or c = 2 or c = 3", + "Best": "IndexReader(Index(t.c_d_e)[[1,3]])->Projection" + }, + { + "SQL": "select b from t where c = 1 or c = 2 or c = 3 or c = 4 or c = 5", + "Best": "IndexLookUp(Index(t.c_d_e)[[1,5]], Table(t))->Projection" + }, + { + "SQL": "select a from t where c = 5", + "Best": "IndexReader(Index(t.c_d_e)[[5,5]])->Projection" + }, + { + "SQL": "select a from t where c = 5 and b = 1", + "Best": "IndexLookUp(Index(t.c_d_e)[[5,5]], Table(t)->Sel([eq(Column#2, 1)]))->Projection" + }, + { + "SQL": "select a from t where not a", + "Best": "IndexReader(Index(t.f)[[NULL,+inf]]->Sel([not(Column#1)]))" + }, + { + "SQL": "select a from t where c in (1)", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])->Projection" + }, + { + "SQL": "select a from t where c in ('1')", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])->Projection" + }, + { + "SQL": "select a from t where c = 1.0", + "Best": "IndexReader(Index(t.c_d_e)[[1,1]])->Projection" + }, + { + "SQL": "select a from t where c in (1) and d > 3", + "Best": "IndexReader(Index(t.c_d_e)[(1 3,1 +inf]])->Projection" + }, + { + "SQL": "select a from t where c in (1, 2, 3) and (d > 3 and d < 4 or d > 5 and d < 6)", + "Best": "Dual->Projection" + }, + { + "SQL": "select a from t where c in (1, 2, 3) and (d > 2 and d < 4 or d > 5 and d < 7)", + "Best": "IndexReader(Index(t.c_d_e)[(1 2,1 4) (1 5,1 7) (2 2,2 4) (2 5,2 7) (3 2,3 4) (3 5,3 7)])->Projection" + }, + { + "SQL": "select a from t where c in (1, 2, 3)", + "Best": "IndexReader(Index(t.c_d_e)[[1,1] [2,2] [3,3]])->Projection" + }, + { + "SQL": "select a from t where c in (1, 2, 3) and d in (1,2) and e = 1", + "Best": "IndexReader(Index(t.c_d_e)[[1 1 1,1 1 1] [1 2 1,1 2 1] [2 1 1,2 1 1] [2 2 1,2 2 1] [3 1 1,3 1 1] [3 2 1,3 2 1]])->Projection" + }, + { + "SQL": "select a from t where d in (1, 2, 3)", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]]->Sel([in(Column#4, 1, 2, 3)]))->Projection" + }, + { + "SQL": "select a from t where c not in (1)", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,1) (1,+inf]])->Projection" + }, + { + "SQL": "select a from t use index(c_d_e) where c != 1", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,1) (1,+inf]])->Projection" + }, + { + "SQL": "select a from t where c_str like ''", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"\",\"\"]])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc'", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc\",\"abc\"]])->Projection" + }, + { + "SQL": "select a from t where c_str not like 'abc'", + "Best": "IndexReader(Index(t.c_d_e_str)[[-inf,\"abc\") (\"abc\",+inf]])->Projection" + }, + { + "SQL": "select a from t where not (c_str like 'abc' or c_str like 'abd')", + "Best": "IndexReader(Index(t.c_d_e_str)[[-inf,\"abc\") (\"abc\",\"abd\") (\"abd\",+inf]])->Projection" + }, + { + "SQL": "select a from t where c_str like '_abc'", + "Best": "IndexReader(Index(t.c_d_e_str)[[NULL,+inf]]->Sel([like(Column#6, _abc, 92)]))->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc%'", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc\",\"abd\")])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc_'", + "Best": "IndexReader(Index(t.c_d_e_str)[(\"abc\",\"abd\")]->Sel([like(Column#6, abc_, 92)]))->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc%af'", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc\",\"abd\")]->Sel([like(Column#6, abc%af, 92)]))->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc\\_' escape ''", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc_\",\"abc_\"]])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc\\_'", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc_\",\"abc_\"]])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc\\\\_'", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc_\",\"abc_\"]])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc\\_%'", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc_\",\"abc`\")])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc=_%' escape '='", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"abc_\",\"abc`\")])->Projection" + }, + { + "SQL": "select a from t where c_str like 'abc\\__'", + "Best": "IndexReader(Index(t.c_d_e_str)[(\"abc_\",\"abc`\")]->Sel([like(Column#6, abc\\__, 92)]))->Projection" + }, + { + "SQL": "select a from t where c_str like 123", + "Best": "IndexReader(Index(t.c_d_e_str)[[\"123\",\"123\"]])->Projection" + }, + { + "SQL": "select a from t where c = 1.9 and d > 3", + "Best": "Dual" + }, + { + "SQL": "select a from t where c < 1.1", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,2)])->Projection" + }, + { + "SQL": "select a from t where c <= 1.9", + "Best": "IndexReader(Index(t.c_d_e)[[-inf,1]])->Projection" + }, + { + "SQL": "select a from t where c >= 1.1", + "Best": "IndexReader(Index(t.c_d_e)[[2,+inf]])->Projection" + }, + { + "SQL": "select a from t where c > 1.9", + "Best": "IndexReader(Index(t.c_d_e)[(1,+inf]])->Projection" + }, + { + "SQL": "select a from t where c = 123456789098765432101234", + "Best": "Dual" + }, + { + "SQL": "select a from t where c = 'hanfei'", + "Best": "IndexReader(Index(t.c_d_e)[[NULL,+inf]])->Sel([eq(cast(Column#3), cast(hanfei))])->Projection" + } + ] + }, + { + "Name": "TestAggEliminator", + "Cases": [ + { + "SQL": "select max(a) from t;", + "Best": "TableReader(Table(t)->Limit)->Limit->StreamAgg" + }, + { + "SQL": "select min(a) from t;", + "Best": "TableReader(Table(t)->Limit)->Limit->StreamAgg" + }, + { + "SQL": "select min(c_str) from t;", + "Best": "IndexReader(Index(t.c_d_e_str)[[-inf,+inf]]->Limit)->Limit->StreamAgg" + }, + { + "SQL": "select max(a), b from t;", + "Best": "TableReader(Table(t)->StreamAgg)->StreamAgg" + }, + { + "SQL": "select max(a+1) from t;", + "Best": "IndexReader(Index(t.f)[[NULL,+inf]]->Sel([not(isnull(plus(Column#1, 1)))])->TopN([plus(Column#1, 1) true],0,1))->Projection->TopN([Column#15 true],0,1)->Projection->Projection->StreamAgg" + }, + { + "SQL": "select max(a), min(a) from t;", + "Best": "LeftHashJoin{TableReader(Table(t)->Limit)->Limit->StreamAgg->TableReader(Table(t)->Limit)->Limit->StreamAgg}" + }, + { + "SQL": "select max(a), min(a) from t where a > 10", + "Best": "LeftHashJoin{TableReader(Table(t)->Limit)->Limit->StreamAgg->TableReader(Table(t)->Limit)->Limit->StreamAgg}" + }, + { + "SQL": "select max(d), min(d) from t where c = 1 and d > 10", + "Best": "LeftHashJoin{IndexReader(Index(t.c_d_e)[(1 10,1 +inf]]->Limit)->Limit->StreamAgg->IndexReader(Index(t.c_d_e)[(1 10,1 +inf]]->Limit)->Limit->StreamAgg}" + }, + { + "SQL": "select max(a), max(c), min(f) from t", + "Best": "LeftHashJoin{LeftHashJoin{TableReader(Table(t)->Limit)->Limit->StreamAgg->IndexReader(Index(t.c_d_e)[[NULL,+inf]]->Limit)->Limit->StreamAgg}->IndexReader(Index(t.f)[[NULL,+inf]]->Limit)->Limit->StreamAgg}" + }, + { + "SQL": "select max(a), max(b) from t", + "Best": "TableReader(Table(t)->StreamAgg)->StreamAgg" + }, + { + "SQL": "select max(a), max(c) from t where c > 10", + "Best": "IndexReader(Index(t.c_d_e)[(10,+inf]]->StreamAgg)->StreamAgg" + }, + { + "SQL": "select max(a), min(a) from t where a * 3 + 10 < 100", + "Best": "IndexReader(Index(t.f)[[NULL,+inf]]->Sel([lt(plus(mul(Column#1, 3), 10), 100)])->StreamAgg)->StreamAgg" + }, + { + "SQL": "select max(a) from t group by b;", + "Best": "TableReader(Table(t)->HashAgg)->HashAgg" + }, + { + "SQL": "select max(a) from (select t1.a from t t1 join t t2 on t1.a=t2.a) t", + "Best": "IndexMergeJoin{TableReader(Table(t))->TableReader(Table(t))}(Column#1,Column#13)->Limit->StreamAgg" + } + ] + }, + { + "Name": "TestUnmatchedTableInHint", + "Cases": [ + { + "SQL": "SELECT /*+ TIDB_SMJ(t3, t4) */ * from t t1, t t2 where t1.a = t2.a", + "Warning": "[planner:1815]There are no matching table names for (t3, t4) in optimizer hint /*+ SM_JOIN(t3, t4) */ or /*+ TIDB_SMJ(t3, t4) */. Maybe you can use the table alias name" + }, + { + "SQL": "SELECT /*+ TIDB_HJ(t3, t4) */ * from t t1, t t2 where t1.a = t2.a", + "Warning": "[planner:1815]There are no matching table names for (t3, t4) in optimizer hint /*+ HASH_JOIN(t3, t4) */ or /*+ TIDB_HJ(t3, t4) */. Maybe you can use the table alias name" + }, + { + "SQL": "SELECT /*+ TIDB_INLJ(t3, t4) */ * from t t1, t t2 where t1.a = t2.a", + "Warning": "[planner:1815]There are no matching table names for (t3, t4) in optimizer hint /*+ INL_JOIN(t3, t4) */ or /*+ TIDB_INLJ(t3, t4) */. Maybe you can use the table alias name" + }, + { + "SQL": "SELECT /*+ TIDB_SMJ(t1, t2) */ * from t t1, t t2 where t1.a = t2.a", + "Warning": "" + }, + { + "SQL": "SELECT /*+ TIDB_SMJ(t3, t4) */ * from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a", + "Warning": "[planner:1815]There are no matching table names for (t4) in optimizer hint /*+ SM_JOIN(t3, t4) */ or /*+ TIDB_SMJ(t3, t4) */. Maybe you can use the table alias name" + } + ] + }, + { + "Name": "TestJoinHints", + "Cases": [ + { + "SQL": "select /*+ TIDB_INLJ(t1) */ t1.a, t2.a, t3.a from t t1, t t2, t t3 where t1.a = t2.a and t2.a = t3.a;", + "Best": "RightHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#13,Column#1)}(Column#25,Column#13)->Projection", + "Warning": "", + "Hints": "USE_INDEX(@`sel_1` `t3` `f`), USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_1` `t2` `f`), INL_JOIN(@`sel_1` `t1`), HASH_JOIN(@`sel_1` `t3`)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1) */ t1.b, t2.a from t t1, t t2 where t1.b = t2.a;", + "Best": "LeftHashJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#2,Column#13)", + "Warning": "[planner:1815]Optimizer Hint /*+ INL_JOIN(t1) */ or /*+ TIDB_INLJ(t1) */ is inapplicable", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_1` `t2` `f`), HASH_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t2) */ t1.b, t2.a from t2 t1, t2 t2 where t1.b=t2.b and t2.c=-1;", + "Best": "IndexJoin{IndexReader(Index(t2.b)[[NULL,+inf]])->TableReader(Table(t2)->Sel([eq(Column#6, -1)]))}(Column#5,Column#2)->Projection", + "Warning": "[planner:1815]Optimizer Hint /*+ INL_JOIN(t2) */ or /*+ TIDB_INLJ(t2) */ is inapplicable", + "Hints": "USE_INDEX(@`sel_1` `t1` `b`), USE_INDEX(@`sel_1` `t2` ), INL_JOIN(@`sel_1` `t1`)" + } + ] + }, + { + "Name": "TestAggregationHints", + "Cases": [ + { + "SQL": "select count(*) from t t1, t t2 where t1.a = t2.b", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->StreamAgg", + "Warning": "" + }, + { + "SQL": "select count(t1.a) from t t1, t t2 where t1.a = t2.a*2 group by t1.a", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]])->Projection}(Column#1,Column#27)->HashAgg", + "Warning": "" + }, + { + "SQL": "select /*+ HASH_AGG() */ count(*) from t t1, t t2 where t1.a = t2.b", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->HashAgg", + "Warning": "" + }, + { + "SQL": "select /*+ STREAM_AGG() */ count(t1.a) from t t1, t t2 where t1.a = t2.a*2 group by t1.a", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]])->Projection}(Column#1,Column#27)->Sort->StreamAgg", + "Warning": "" + }, + { + "SQL": "select /*+ HASH_AGG() STREAM_AGG() */ count(*) from t t1, t t2 where t1.a = t2.b", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->StreamAgg", + "Warning": "[planner:1815]Optimizer aggregation hints are conflicted" + }, + { + "SQL": "select /*+ STREAM_AGG() */ distinct a from t", + "Best": "TableReader(Table(t))->StreamAgg", + "Warning": "" + }, + { + "SQL": "select /*+ HASH_AGG() */ t1.a from t t1 where t1.a < any(select t2.b from t t2)", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]]->Sel([if(isnull(Column#1), , 1)]))->TableReader(Table(t)->HashAgg)->HashAgg->Sel([ne(Column#28, 0)])}->Projection->Projection", + "Warning": "" + }, + { + "SQL": "select /*+ hash_agg() */ t1.a from t t1 where t1.a != any(select t2.b from t t2)", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]]->Sel([if(isnull(Column#1), , 1)]))->TableReader(Table(t))->Projection->HashAgg->Sel([ne(Column#29, 0)])}->Projection->Projection", + "Warning": "" + }, + { + "SQL": "select /*+ hash_agg() */ t1.a from t t1 where t1.a = all(select t2.b from t t2)", + "Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))->Projection->HashAgg}->Projection->Projection", + "Warning": "" + }, + { + "SQL": "select /*+ STREAM_AGG() */ sum(t1.a) from t t1 join t t2 on t1.b = t2.b group by t1.b", + "Best": "LeftHashJoin{TableReader(Table(t))->TableReader(Table(t))->Sort->Projection->StreamAgg}(Column#14,Column#2)->HashAgg", + "Warning": "[planner:1815]Optimizer Hint STREAM_AGG is inapplicable" + }, + { + "SQL": "select /*+ STREAM_AGG() */ e, sum(b) from t group by e", + "Best": "TableReader(Table(t))->Sort->Projection->StreamAgg->Projection", + "Warning": "" + } + ] + }, + { + "Name": "TestQueryBlockHint", + "Cases": [ + { + "SQL": "select /*+ SM_JOIN(@sel_1 t1), INL_JOIN(@sel_2 t3) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Plan": "MergeInnerJoin{TableReader(Table(t))->IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t2` ), USE_INDEX(@`sel_2` `t3` `c_d_e`), INL_JOIN(@`sel_2` `t3`), SM_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ SM_JOIN(@sel_1 t1), INL_JOIN(@qb t3) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Plan": "MergeInnerJoin{TableReader(Table(t))->IndexMergeJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t2` ), USE_INDEX(@`sel_2` `t3` `c_d_e`), INL_JOIN(@`sel_2` `t3`), SM_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ HASH_JOIN(@sel_1 t1), SM_JOIN(@sel_2 t2) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Plan": "RightHashJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t2` ), USE_INDEX(@`sel_2` `t3` `c_d_e`), SM_JOIN(@`sel_2` `t2`), HASH_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ HASH_JOIN(@sel_1 t1), SM_JOIN(@qb t2) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Plan": "RightHashJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t2` ), USE_INDEX(@`sel_2` `t3` `c_d_e`), SM_JOIN(@`sel_2` `t2`), HASH_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ INL_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t2) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Plan": "IndexMergeJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#13,Column#1)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t2` `f`), USE_INDEX(@`sel_2` `t3` `c_d_e`), HASH_JOIN(@`sel_2` `t2`), INL_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ INL_JOIN(@sel_1 t1), HASH_JOIN(@qb t2) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", + "Plan": "IndexMergeJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#13,Column#1)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t2` `f`), USE_INDEX(@`sel_2` `t3` `c_d_e`), HASH_JOIN(@`sel_2` `t2`), INL_JOIN(@`sel_1` `t1`)" + }, + { + "SQL": "select /*+ HASH_AGG(@sel_1), STREAM_AGG(@sel_2) */ count(*) from t t1 where t1.a < (select count(*) from t t2 where t1.a > t2.a)", + "Plan": "Apply{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]]->Sel([gt(Column#1, Column#13)])->StreamAgg)->StreamAgg->Sel([not(isnull(Column#25))])}->HashAgg", + "Hints": "USE_INDEX(@`sel_1` `t1` `f`), USE_INDEX(@`sel_2` `t2` `f`), STREAM_AGG(@`sel_2`), HASH_AGG(@`sel_1`)" + }, + { + "SQL": "select /*+ STREAM_AGG(@sel_1), HASH_AGG(@qb) */ count(*) from t t1 where t1.a < (select /*+ QB_NAME(qb) */ count(*) from t t2 where t1.a > t2.a)", + "Plan": "Apply{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]]->Sel([gt(Column#1, Column#13)])->HashAgg)->HashAgg->Sel([not(isnull(Column#25))])}->StreamAgg", + "Hints": "USE_INDEX(@`sel_1` `t1` `f`), USE_INDEX(@`sel_2` `t2` `f`), HASH_AGG(@`sel_2`), STREAM_AGG(@`sel_1`)" + }, + { + "SQL": "select /*+ HASH_AGG(@sel_2) */ a, (select count(*) from t t1 where t1.b > t.a) from t where b > (select b from t t2 where t2.b = t.a limit 1)", + "Plan": "Apply{Apply{TableReader(Table(t))->TableReader(Table(t)->Sel([eq(Column#14, Column#1)])->Limit)->Limit}->TableReader(Table(t)->Sel([gt(Column#28, Column#1)])->HashAgg)->HashAgg}->Projection", + "Hints": "USE_INDEX(@`sel_1` `t` ), USE_INDEX(@`sel_3` `t2` ), USE_INDEX(@`sel_2` `t1` ), HASH_AGG(@`sel_2`)" + }, + { + "SQL": "select /*+ HASH_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t1) */ t1.b, t2.a, t2.aa from t t1, (select t1.a as a, t2.a as aa from t t1, t t2) t2 where t1.a = t2.aa;", + "Plan": "RightHashJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]])}}(Column#1,Column#25)->Projection", + "Hints": "USE_INDEX(@`sel_1` `t1` ), USE_INDEX(@`sel_2` `t1` `f`), USE_INDEX(@`sel_2` `t2` `f`), HASH_JOIN(@`sel_2` `t1`), HASH_JOIN(@`sel_1` `t1`)" + } + ] + }, + { + "Name": "TestIndexJoinUnionScan", + "Cases": [ + { + "SQL": "select /*+ TIDB_INLJ(t2) */ * from t t1, t t2 where t1.a = t2.a", + "Best": "IndexJoin{TableReader(Table(t))->UnionScan([])->TableReader(Table(t))->UnionScan([])}(Column#1,Column#13)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ * from t t1, t t2 where t1.a = t2.c", + "Best": "IndexJoin{TableReader(Table(t))->UnionScan([])->TableReader(Table(t))->UnionScan([])}(Column#15,Column#1)" + }, + { + "SQL": "select /*+ TIDB_INLJ(t1, t2) */ t1.a , t2.c from t t1, t t2 where t1.a = t2.c", + "Best": "IndexJoin{IndexReader(Index(t.f)[[NULL,+inf]])->UnionScan([])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])->UnionScan([])}(Column#1,Column#15)->Projection" + } + ] + }, + { + "Name": "TestSemiJoinToInner", + "Cases": [ + { + "SQL": "select t1.a, (select count(t2.a) from t t2 where t2.g in (select t3.d from t t3 where t3.c = t1.a)) as agg_col from t t1;", + "Best": "Apply{IndexReader(Index(t.f)[[NULL,+inf]])->IndexMergeJoin{IndexReader(Index(t.c_d_e)[[NULL,+inf]]->HashAgg)->HashAgg->IndexReader(Index(t.g)[[NULL,+inf]])}(Column#29,Column#23)}->HashAgg" + } + ] + }, + { + "Name": "TestSimplifyOuterJoinWithCast", + "Cases": [ + { + "SQL": "select * from t t1 left join t t2 on t1.a = t2.a where cast(t1.c_str as float) = '2.3'", + "Best": "MergeLeftOuterJoin{TableReader(Table(t))->Sel([eq(cast(Column#6), 2.3)])->TableReader(Table(t))}(Column#1,Column#13)" + } + ] + } +]