Files
tidb/plan/explain_test.go

275 lines
11 KiB
Go

// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package plan_test
import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/util/testkit"
"github.com/pingcap/tidb/util/testleak"
)
var _ = Suite(&testExplainSuite{})
type testExplainSuite struct {
}
func (s *testExplainSuite) TestExplain(c *C) {
store, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
tk := testkit.NewTestKit(c, store)
defer func() {
testleak.AfterTest(c)()
}()
tk.MustExec("use test")
tk.MustExec("drop table if exists t1, t2, t3")
tk.MustExec("create table t1 (c1 int primary key, c2 int, c3 int, index c2 (c2))")
tk.MustExec("create table t2 (c1 int unique, c2 int)")
tk.MustExec("insert into t2 values(1, 0), (2, 1)")
tk.MustExec("create table t3 (a bigint, b bigint, c bigint, d bigint)")
tests := []struct {
sql string
expect []string
}{
{
"select * from t3 where exists (select s.a from t3 s having sum(s.a) = t3.a )",
[]string{
"TableScan_15 cop table:t3, range:(-inf,+inf), keep order:false 8000",
"TableReader_16 Projection_12 root data:TableScan_15 8000",
"Projection_12 HashSemiJoin_14 TableReader_16 root test.t3.a, test.t3.b, test.t3.c, test.t3.d, cast(test.t3.a) 8000",
"TableScan_18 HashAgg_17 cop table:s, range:(-inf,+inf), keep order:false 8000",
"HashAgg_17 TableScan_18 cop type:complete, funcs:sum(s.a) 1",
"TableReader_20 HashAgg_19 root data:HashAgg_17 1",
"HashAgg_19 HashSemiJoin_14 TableReader_20 root type:final, funcs:sum(col_0) 1",
"HashSemiJoin_14 Projection_11 Projection_12,HashAgg_19 root right:HashAgg_19, equal:[eq(cast(test.t3.a), sel_agg_1)] 6400",
"Projection_11 HashSemiJoin_14 root test.t3.a, test.t3.b, test.t3.c, test.t3.d 6400",
},
},
{
"select * from t1",
[]string{
"TableScan_3 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"TableReader_4 root data:TableScan_3 8000",
},
},
{
"select * from t1 order by c2",
[]string{
"IndexScan_10 cop table:t1, index:c2, range:[<nil>,+inf], out of order:false 8000",
"TableScan_11 cop table:t1, keep order:false 8000",
"IndexLookUp_12 root index:IndexScan_10, table:TableScan_11 8000",
},
},
{
"select * from t2 order by c2",
[]string{
"TableScan_4 cop table:t2, range:(-inf,+inf), keep order:false 8000",
"TableReader_5 Sort_3 root data:TableScan_4 8000",
"Sort_3 TableReader_5 root t2.c2:asc 8000",
},
},
{
"select * from t1 where t1.c1 > 0",
[]string{
"TableScan_4 cop table:t1, range:[1,+inf), keep order:false 3333.333333333333",
"TableReader_5 root data:TableScan_4 3333.333333333333",
},
},
{
"select t1.c1, t1.c2 from t1 where t1.c2 = 1",
[]string{
"IndexScan_7 cop table:t1, index:c2, range:[1,1], out of order:true 10",
"IndexReader_8 root index:IndexScan_7 10",
},
},
{
"select * from t1 left join t2 on t1.c2 = t2.c1 where t1.c1 > 1",
[]string{
"TableScan_25 cop table:t1, range:[2,+inf), keep order:false 3333.333333333333",
"TableReader_26 HashLeftJoin_11 root data:TableScan_25 3333.333333333333",
"TableScan_31 cop table:t2, range:(-inf,+inf), keep order:false 8000",
"TableReader_32 HashLeftJoin_11 root data:TableScan_31 8000",
"HashLeftJoin_11 TableReader_26,TableReader_32 root left outer join, small:TableReader_32, equal:[eq(test.t1.c2, test.t2.c1)] 4166.666666666666",
},
},
{
"update t1 set t1.c2 = 2 where t1.c1 = 1",
[]string{
"TableScan_4 cop table:t1, range:[1,1], keep order:false 10",
"TableReader_5 Update_3 root data:TableScan_4 10",
"Update_3 TableReader_5 root 10",
},
},
{
"delete from t1 where t1.c2 = 1",
[]string{
"IndexScan_7 cop table:t1, index:c2, range:[1,1], out of order:true 10",
"TableScan_8 cop table:t1, keep order:false 10",
"IndexLookUp_9 Delete_3 root index:IndexScan_7, table:TableScan_8 10",
"Delete_3 IndexLookUp_9 root 10",
},
},
{
"select count(b.c2) from t1 a, t2 b where a.c1 = b.c2 group by a.c1",
[]string{
"TableScan_21 cop table:a, range:(-inf,+inf), keep order:false 8000",
"TableReader_22 HashLeftJoin_13 root data:TableScan_21 8000",
"TableScan_16 HashAgg_15 cop table:b, range:(-inf,+inf), keep order:false 8000",
"HashAgg_15 TableScan_16 cop type:complete, group by:b.c2, funcs:count(b.c2), firstrow(b.c2) 6400",
"TableReader_18 HashAgg_17 root data:HashAgg_15 6400",
"HashAgg_17 HashLeftJoin_13 TableReader_18 root type:final, group by:, funcs:count(col_0), firstrow(col_1) 6400",
"HashLeftJoin_13 Projection_9 TableReader_22,HashAgg_17 root inner join, small:HashAgg_17, equal:[eq(a.c1, b.c2)] 8000",
"Projection_9 HashLeftJoin_13 root cast(join_agg_0) 8000",
},
},
{
"select * from t2 order by t2.c2 limit 0, 1",
[]string{
"TableScan_7 TopN_5 cop table:t2, range:(-inf,+inf), keep order:false 8000",
"TopN_5 TableScan_7 cop 1",
"TableReader_8 TopN_5 root data:TopN_5 1",
"TopN_5 TableReader_8 root 1",
},
},
{
"select * from t1 where c1 > 1 and c2 = 1 and c3 < 1",
[]string{
"IndexScan_7 Selection_9 cop table:t1, index:c2, range:[1,1], out of order:true 10",
"Selection_9 IndexScan_7 cop gt(test.t1.c1, 1) 10",
"TableScan_8 Selection_10 cop table:t1, keep order:false 10",
"Selection_10 TableScan_8 cop lt(test.t1.c3, 1) 10",
"IndexLookUp_11 root index:Selection_9, table:Selection_10 10",
},
},
{
"select * from t1 where c1 = 1 and c2 > 1",
[]string{
"TableScan_4 Selection_5 cop table:t1, range:[1,1], keep order:false 10",
"Selection_5 TableScan_4 cop gt(test.t1.c2, 1) 10",
"TableReader_6 root data:Selection_5 10",
},
},
{
"select sum(t1.c1 in (select c1 from t2)) from t1",
[]string{
"TableScan_9 HashAgg_8 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"HashAgg_8 TableScan_9 cop type:complete, funcs:sum(or(eq(test.t1.c1, 1), eq(test.t1.c1, 2))) 1",
"TableReader_11 HashAgg_10 root data:HashAgg_8 1",
"HashAgg_10 TableReader_11 root type:final, funcs:sum(col_0) 1",
},
},
{
"select c1 from t1 where c1 in (select c2 from t2)",
[]string{
"TableScan_8 cop table:t1, range:[0,0], [1,1], keep order:false 20",
"TableReader_9 root data:TableScan_8 20",
},
},
{
"select (select count(1) k from t1 s where s.c1 = t1.c1 having k != 0) from t1",
[]string{
"TableScan_13 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"TableReader_14 Apply_12 root data:TableScan_13 8000",
"TableScan_16 cop table:s, range:(-inf,+inf), keep order:false 8000",
"TableReader_17 Selection_4 root data:TableScan_16 8000",
"Selection_4 HashAgg_15 TableReader_17 root eq(s.c1, test.t1.c1) 6400",
"HashAgg_15 Selection_10 Selection_4 root type:complete, funcs:count(1) 1",
"Selection_10 Apply_12 HashAgg_15 root ne(k, 0) 0.8",
"Apply_12 Projection_2 TableReader_14,Selection_10 root left outer join, small:Selection_10, right:Selection_10 8000",
"Projection_2 Apply_12 root k 8000",
},
},
{
"select * from information_schema.columns",
[]string{
"MemTableScan_3 root 8000",
},
},
{
"select c2 = (select c2 from t2 where t1.c1 = t2.c1 order by c1 limit 1) from t1",
[]string{
"TableScan_14 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"TableReader_15 Apply_13 root data:TableScan_14 8000",
"IndexScan_23 cop table:t2, index:c1, range:[<nil>,+inf], out of order:false 1.25",
"TableScan_24 cop table:t2, keep order:false 1.25",
"IndexLookUp_25 Selection_4 root index:IndexScan_23, table:TableScan_24 1.25",
"Selection_4 Limit_16 IndexLookUp_25 root eq(test.t1.c1, test.t2.c1) 6400",
"Limit_16 MaxOneRow_9 Selection_4 root offset:0, count:1 1",
"MaxOneRow_9 Apply_13 Limit_16 root 1",
"Apply_13 Projection_2 TableReader_15,MaxOneRow_9 root left outer join, small:MaxOneRow_9, right:MaxOneRow_9 8000",
"Projection_2 Apply_13 root eq(test.t1.c2, test.t2.c2) 8000",
},
},
{
"select * from t1 order by c1 desc limit 1",
[]string{
"TableScan_11 Limit_14 cop table:t1, range:(-inf,+inf), keep order:true, desc 1.25",
"Limit_14 TableScan_11 cop offset:0, count:1 1",
"TableReader_15 Limit_6 root data:Limit_14 1",
"Limit_6 TableReader_15 root offset:0, count:1 1",
},
},
}
tk.MustExec("set @@session.tidb_opt_insubquery_unfold = 1")
for _, tt := range tests {
result := tk.MustQuery("explain " + tt.sql)
result.Check(testkit.Rows(tt.expect...))
}
insubqueryFoldTests := []struct {
sql string
expect []string
}{
{
"select sum(t1.c1 in (select c1 from t2)) from t1",
[]string{
"TableScan_10 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"TableReader_11 HashSemiJoin_9 root data:TableScan_10 8000",
"TableScan_12 cop table:t2, range:(-inf,+inf), keep order:false 8000",
"TableReader_13 HashSemiJoin_9 root data:TableScan_12 8000",
"HashSemiJoin_9 HashAgg_8 TableReader_11,TableReader_13 root right:TableReader_13, aux, equal:[eq(test.t1.c1, test.t2.c1)] 8000",
"HashAgg_8 HashSemiJoin_9 root type:complete, funcs:sum(5_aux_0) 1",
},
},
{
"select 1 in (select c2 from t2) from t1",
[]string{
"TableScan_8 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"TableReader_9 HashSemiJoin_7 root data:TableScan_8 8000",
"TableScan_10 Selection_11 cop table:t2, range:(-inf,+inf), keep order:false 10",
"Selection_11 TableScan_10 cop eq(1, test.t2.c2) 10",
"TableReader_12 HashSemiJoin_7 root data:Selection_11 10",
"HashSemiJoin_7 TableReader_9,TableReader_12 root right:TableReader_12, aux 8000",
},
},
{
"select sum(6 in (select c2 from t2)) from t1",
[]string{
"TableScan_10 cop table:t1, range:(-inf,+inf), keep order:false 8000",
"TableReader_11 HashSemiJoin_9 root data:TableScan_10 8000",
"TableScan_12 Selection_13 cop table:t2, range:(-inf,+inf), keep order:false 10",
"Selection_13 TableScan_12 cop eq(6, test.t2.c2) 10",
"TableReader_14 HashSemiJoin_9 root data:Selection_13 10",
"HashSemiJoin_9 HashAgg_8 TableReader_11,TableReader_14 root right:TableReader_14, aux 8000",
"HashAgg_8 HashSemiJoin_9 root type:complete, funcs:sum(5_aux_0) 1",
},
},
}
tk.MustExec("set @@session.tidb_opt_insubquery_unfold = 0")
for _, tt := range insubqueryFoldTests {
result := tk.MustQuery("explain " + tt.sql)
result.Check(testkit.Rows(tt.expect...))
}
}