github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/plan_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by aprettyPrintlicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package embedded_test
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    23  	. "github.com/whtcorpsinc/check"
    24  	"github.com/whtcorpsinc/milevadb/causet/embedded"
    25  	"github.com/whtcorpsinc/milevadb/ekv"
    26  	"github.com/whtcorpsinc/milevadb/petri"
    27  	"github.com/whtcorpsinc/milevadb/soliton/israce"
    28  	"github.com/whtcorpsinc/milevadb/soliton/plancodec"
    29  	"github.com/whtcorpsinc/milevadb/soliton/solitonutil"
    30  	"github.com/whtcorpsinc/milevadb/soliton/testkit"
    31  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    32  )
    33  
    34  var _ = Suite(&testCausetNormalize{})
    35  
    36  type testCausetNormalize struct {
    37  	causetstore ekv.CausetStorage
    38  	dom         *petri.Petri
    39  
    40  	testData solitonutil.TestData
    41  }
    42  
    43  func (s *testCausetNormalize) SetUpSuite(c *C) {
    44  	testleak.BeforeTest()
    45  	causetstore, dom, err := newStoreWithBootstrap()
    46  	c.Assert(err, IsNil)
    47  	s.causetstore = causetstore
    48  	s.dom = dom
    49  
    50  	s.testData, err = solitonutil.LoadTestSuiteData("testdata", "plan_normalized_suite")
    51  	c.Assert(err, IsNil)
    52  }
    53  
    54  func (s *testCausetNormalize) TearDownSuite(c *C) {
    55  	c.Assert(s.testData.GenerateOutputIfNeeded(), IsNil)
    56  	s.dom.Close()
    57  	s.causetstore.Close()
    58  	testleak.AfterTest(c)()
    59  }
    60  
    61  func (s *testCausetNormalize) TestNormalizedCauset(c *C) {
    62  	tk := testkit.NewTestKit(c, s.causetstore)
    63  	tk.MustInterDirc("use test")
    64  	tk.MustInterDirc("drop causet if exists t1,t2")
    65  	tk.MustInterDirc("create causet t1 (a int key,b int,c int, index (b));")
    66  	tk.MustInterDirc("create causet t2 (a int key,b int,c int, index (b));")
    67  	var input []string
    68  	var output []struct {
    69  		ALLEGROALLEGROSQL string
    70  		Causet            []string
    71  	}
    72  	s.testData.GetTestCases(c, &input, &output)
    73  	for i, tt := range input {
    74  		tk.Se.GetStochastikVars().CausetID = 0
    75  		tk.MustInterDirc(tt)
    76  		info := tk.Se.ShowProcess()
    77  		c.Assert(info, NotNil)
    78  		p, ok := info.Causet.(embedded.Causet)
    79  		c.Assert(ok, IsTrue)
    80  		normalized, _ := embedded.NormalizeCauset(p)
    81  		normalizedCauset, err := plancodec.DecodeNormalizedCauset(normalized)
    82  		normalizedCausetRows := getCausetRows(normalizedCauset)
    83  		c.Assert(err, IsNil)
    84  		s.testData.OnRecord(func() {
    85  			output[i].ALLEGROALLEGROSQL = tt
    86  			output[i].Causet = normalizedCausetRows
    87  		})
    88  		compareStringSlice(c, normalizedCausetRows, output[i].Causet)
    89  	}
    90  }
    91  
    92  func (s *testCausetNormalize) TestNormalizedCausetForDiffStore(c *C) {
    93  	tk := testkit.NewTestKit(c, s.causetstore)
    94  	tk.MustInterDirc("use test")
    95  	tk.MustInterDirc("drop causet if exists t1")
    96  	tk.MustInterDirc("create causet t1 (a int, b int, c int, primary key(a))")
    97  	tk.MustInterDirc("insert into t1 values(1,1,1), (2,2,2), (3,3,3)")
    98  
    99  	tbl, err := s.dom.SchemaReplicant().BlockByName(perceptron.CIStr{O: "test", L: "test"}, perceptron.CIStr{O: "t1", L: "t1"})
   100  	c.Assert(err, IsNil)
   101  	// Set the reploged TiFlash replica for explain tests.
   102  	tbl.Meta().TiFlashReplica = &perceptron.TiFlashReplicaInfo{Count: 1, Available: true}
   103  
   104  	var input []string
   105  	var output []struct {
   106  		Digest string
   107  		Causet []string
   108  	}
   109  	s.testData.GetTestCases(c, &input, &output)
   110  	lastDigest := ""
   111  	for i, tt := range input {
   112  		tk.Se.GetStochastikVars().CausetID = 0
   113  		tk.MustInterDirc(tt)
   114  		info := tk.Se.ShowProcess()
   115  		c.Assert(info, NotNil)
   116  		ep, ok := info.Causet.(*embedded.Explain)
   117  		c.Assert(ok, IsTrue)
   118  		normalized, digest := embedded.NormalizeCauset(ep.TargetCauset)
   119  		normalizedCauset, err := plancodec.DecodeNormalizedCauset(normalized)
   120  		normalizedCausetRows := getCausetRows(normalizedCauset)
   121  		c.Assert(err, IsNil)
   122  		s.testData.OnRecord(func() {
   123  			output[i].Digest = digest
   124  			output[i].Causet = normalizedCausetRows
   125  		})
   126  		compareStringSlice(c, normalizedCausetRows, output[i].Causet)
   127  		c.Assert(digest != lastDigest, IsTrue)
   128  		lastDigest = digest
   129  	}
   130  }
   131  
   132  func (s *testCausetNormalize) TestEncodeDecodeCauset(c *C) {
   133  	if israce.RaceEnabled {
   134  		c.Skip("skip race test")
   135  	}
   136  	tk := testkit.NewTestKit(c, s.causetstore)
   137  	tk.MustInterDirc("use test")
   138  	tk.MustInterDirc("drop causet if exists t1,t2")
   139  	tk.MustInterDirc("create causet t1 (a int key,b int,c int, index (b));")
   140  	tk.MustInterDirc("set milevadb_enable_collect_execution_info=1;")
   141  
   142  	tk.Se.GetStochastikVars().CausetID = 0
   143  	getCausetTree := func() string {
   144  		info := tk.Se.ShowProcess()
   145  		c.Assert(info, NotNil)
   146  		p, ok := info.Causet.(embedded.Causet)
   147  		c.Assert(ok, IsTrue)
   148  		encodeStr := embedded.EncodeCauset(p)
   149  		planTree, err := plancodec.DecodeCauset(encodeStr)
   150  		c.Assert(err, IsNil)
   151  		return planTree
   152  	}
   153  	tk.MustInterDirc("select max(a) from t1 where a>0;")
   154  	planTree := getCausetTree()
   155  	c.Assert(strings.Contains(planTree, "time"), IsTrue)
   156  	c.Assert(strings.Contains(planTree, "loops"), IsTrue)
   157  
   158  	tk.MustInterDirc("insert into t1 values (1,1,1);")
   159  	planTree = getCausetTree()
   160  	c.Assert(strings.Contains(planTree, "Insert"), IsTrue)
   161  	c.Assert(strings.Contains(planTree, "time"), IsTrue)
   162  	c.Assert(strings.Contains(planTree, "loops"), IsTrue)
   163  }
   164  
   165  func (s *testCausetNormalize) TestNormalizedDigest(c *C) {
   166  	tk := testkit.NewTestKit(c, s.causetstore)
   167  	tk.MustInterDirc("use test")
   168  	tk.MustInterDirc("drop causet if exists t1,t2, bmsql_order_line, bmsql_district,bmsql_stock")
   169  	tk.MustInterDirc("create causet t1 (a int key,b int,c int, index (b));")
   170  	tk.MustInterDirc("create causet t2 (a int key,b int,c int, index (b));")
   171  	tk.MustInterDirc(`CREATE TABLE  bmsql_order_line  (
   172  	   ol_w_id  int(11) NOT NULL,
   173  	   ol_d_id  int(11) NOT NULL,
   174  	   ol_o_id  int(11) NOT NULL,
   175  	   ol_number  int(11) NOT NULL,
   176  	   ol_i_id  int(11) NOT NULL,
   177  	   ol_delivery_d  timestamp NULL DEFAULT NULL,
   178  	   ol_amount  decimal(6,2) DEFAULT NULL,
   179  	   ol_supply_w_id  int(11) DEFAULT NULL,
   180  	   ol_quantity  int(11) DEFAULT NULL,
   181  	   ol_dist_info  char(24) DEFAULT NULL,
   182  	  PRIMARY KEY ( ol_w_id , ol_d_id , ol_o_id , ol_number )
   183  	);`)
   184  	tk.MustInterDirc(`CREATE TABLE  bmsql_district  (
   185  	   d_w_id  int(11) NOT NULL,
   186  	   d_id  int(11) NOT NULL,
   187  	   d_ytd  decimal(12,2) DEFAULT NULL,
   188  	   d_tax  decimal(4,4) DEFAULT NULL,
   189  	   d_next_o_id  int(11) DEFAULT NULL,
   190  	   d_name  varchar(10) DEFAULT NULL,
   191  	   d_street_1  varchar(20) DEFAULT NULL,
   192  	   d_street_2  varchar(20) DEFAULT NULL,
   193  	   d_city  varchar(20) DEFAULT NULL,
   194  	   d_state  char(2) DEFAULT NULL,
   195  	   d_zip  char(9) DEFAULT NULL,
   196  	  PRIMARY KEY ( d_w_id , d_id )
   197  	);`)
   198  	tk.MustInterDirc(`CREATE TABLE  bmsql_stock  (
   199  	   s_w_id  int(11) NOT NULL,
   200  	   s_i_id  int(11) NOT NULL,
   201  	   s_quantity  int(11) DEFAULT NULL,
   202  	   s_ytd  int(11) DEFAULT NULL,
   203  	   s_order_cnt  int(11) DEFAULT NULL,
   204  	   s_remote_cnt  int(11) DEFAULT NULL,
   205  	   s_data  varchar(50) DEFAULT NULL,
   206  	   s_dist_01  char(24) DEFAULT NULL,
   207  	   s_dist_02  char(24) DEFAULT NULL,
   208  	   s_dist_03  char(24) DEFAULT NULL,
   209  	   s_dist_04  char(24) DEFAULT NULL,
   210  	   s_dist_05  char(24) DEFAULT NULL,
   211  	   s_dist_06  char(24) DEFAULT NULL,
   212  	   s_dist_07  char(24) DEFAULT NULL,
   213  	   s_dist_08  char(24) DEFAULT NULL,
   214  	   s_dist_09  char(24) DEFAULT NULL,
   215  	   s_dist_10  char(24) DEFAULT NULL,
   216  	  PRIMARY KEY ( s_w_id , s_i_id )
   217  	);`)
   218  	normalizedDigestCases := []struct {
   219  		sql1   string
   220  		sql2   string
   221  		isSame bool
   222  	}{
   223  		{
   224  			sql1:   "select * from t1;",
   225  			sql2:   "select * from t2;",
   226  			isSame: false,
   227  		},
   228  		{ // test for blockReader and blockScan.
   229  			sql1:   "select * from t1 where a<1",
   230  			sql2:   "select * from t1 where a<2",
   231  			isSame: true,
   232  		},
   233  		{
   234  			sql1:   "select * from t1 where a<1",
   235  			sql2:   "select * from t1 where a=2",
   236  			isSame: false,
   237  		},
   238  		{ // test for point get.
   239  			sql1:   "select * from t1 where a=3",
   240  			sql2:   "select * from t1 where a=2",
   241  			isSame: true,
   242  		},
   243  		{ // test for indexLookUp.
   244  			sql1:   "select * from t1 use index(b) where b=3",
   245  			sql2:   "select * from t1 use index(b) where b=1",
   246  			isSame: true,
   247  		},
   248  		{ // test for indexReader.
   249  			sql1:   "select a+1,b+2 from t1 use index(b) where b=3",
   250  			sql2:   "select a+2,b+3 from t1 use index(b) where b=2",
   251  			isSame: true,
   252  		},
   253  		{ // test for merge join.
   254  			sql1:   "SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>1;",
   255  			sql2:   "SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>2;",
   256  			isSame: true,
   257  		},
   258  		{ // test for indexLookUpJoin.
   259  			sql1:   "SELECT /*+ MilevaDB_INLJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>1;",
   260  			sql2:   "SELECT /*+ MilevaDB_INLJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>3;",
   261  			isSame: true,
   262  		},
   263  		{ // test for hashJoin.
   264  			sql1:   "SELECT /*+ MilevaDB_HJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>1;",
   265  			sql2:   "SELECT /*+ MilevaDB_HJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>3;",
   266  			isSame: true,
   267  		},
   268  		{ // test for diff join.
   269  			sql1:   "SELECT /*+ MilevaDB_HJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>1;",
   270  			sql2:   "SELECT /*+ MilevaDB_INLJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>3;",
   271  			isSame: false,
   272  		},
   273  		{ // test for diff join.
   274  			sql1:   "SELECT /*+ MilevaDB_INLJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>1;",
   275  			sql2:   "SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1, t2 where t1.a = t2.a and t1.c>3;",
   276  			isSame: false,
   277  		},
   278  		{ // test for apply.
   279  			sql1:   "select * from t1 where t1.b > 0 and  t1.a in (select sum(t2.b) from t2 where t2.a=t1.a and t2.b is not null and t2.c >1)",
   280  			sql2:   "select * from t1 where t1.b > 1 and  t1.a in (select sum(t2.b) from t2 where t2.a=t1.a and t2.b is not null and t2.c >0)",
   281  			isSame: true,
   282  		},
   283  		{ // test for apply.
   284  			sql1:   "select * from t1 where t1.b > 0 and  t1.a in (select sum(t2.b) from t2 where t2.a=t1.a and t2.b is not null and t2.c >1)",
   285  			sql2:   "select * from t1 where t1.b > 1 and  t1.a in (select sum(t2.b) from t2 where t2.a=t1.a and t2.b is not null)",
   286  			isSame: false,
   287  		},
   288  		{ // test for topN.
   289  			sql1:   "SELECT * from t1 where a!=1 order by c limit 1",
   290  			sql2:   "SELECT * from t1 where a!=2 order by c limit 2",
   291  			isSame: true,
   292  		},
   293  		{ // test for union
   294  			sql1:   "select count(1) as num,a from t1 where a=1 group by a union select count(1) as num,a from t1 where a=3 group by a;",
   295  			sql2:   "select count(1) as num,a from t1 where a=2 group by a union select count(1) as num,a from t1 where a=4 group by a;",
   296  			isSame: true,
   297  		},
   298  		{
   299  			sql1: `SELECT  COUNT(*) AS low_stock
   300  					FROM
   301  					(
   302  						SELECT  *
   303  						FROM bmsql_stock
   304  						WHERE s_w_id = 1
   305  						AND s_quantity < 2
   306  						AND s_i_id IN ( SELECT /*+ MilevaDB_INLJ(bmsql_order_line) */ ol_i_id FROM bmsql_district JOIN bmsql_order_line ON ol_w_id = d_w_id AND ol_d_id = d_id AND ol_o_id >= d_next_o_id - 20 AND ol_o_id < d_next_o_id WHERE d_w_id = 1 AND d_id = 2 )
   307  					) AS L;`,
   308  			sql2: `SELECT  COUNT(*) AS low_stock
   309  					FROM
   310  					(
   311  						SELECT  *
   312  						FROM bmsql_stock
   313  						WHERE s_w_id = 5
   314  						AND s_quantity < 6
   315  						AND s_i_id IN ( SELECT /*+ MilevaDB_INLJ(bmsql_order_line) */ ol_i_id FROM bmsql_district JOIN bmsql_order_line ON ol_w_id = d_w_id AND ol_d_id = d_id AND ol_o_id >= d_next_o_id - 70 AND ol_o_id < d_next_o_id WHERE d_w_id = 5 AND d_id = 6 )
   316  					) AS L;`,
   317  			isSame: true,
   318  		},
   319  	}
   320  	for _, testCase := range normalizedDigestCases {
   321  		testNormalizeDigest(tk, c, testCase.sql1, testCase.sql2, testCase.isSame)
   322  	}
   323  }
   324  
   325  func testNormalizeDigest(tk *testkit.TestKit, c *C, sql1, sql2 string, isSame bool) {
   326  	tk.Se.GetStochastikVars().CausetID = 0
   327  	tk.MustQuery(sql1)
   328  	info := tk.Se.ShowProcess()
   329  	c.Assert(info, NotNil)
   330  	physicalCauset, ok := info.Causet.(embedded.PhysicalCauset)
   331  	c.Assert(ok, IsTrue)
   332  	normalized1, digest1 := embedded.NormalizeCauset(physicalCauset)
   333  
   334  	tk.Se.GetStochastikVars().CausetID = 0
   335  	tk.MustQuery(sql2)
   336  	info = tk.Se.ShowProcess()
   337  	c.Assert(info, NotNil)
   338  	physicalCauset, ok = info.Causet.(embedded.PhysicalCauset)
   339  	c.Assert(ok, IsTrue)
   340  	normalized2, digest2 := embedded.NormalizeCauset(physicalCauset)
   341  	comment := Commentf("sql1: %v, sql2: %v\n%v !=\n%v\n", sql1, sql2, normalized1, normalized2)
   342  	if isSame {
   343  		c.Assert(normalized1, Equals, normalized2, comment)
   344  		c.Assert(digest1, Equals, digest2, comment)
   345  	} else {
   346  		c.Assert(normalized1 != normalized2, IsTrue, comment)
   347  		c.Assert(digest1 != digest2, IsTrue, comment)
   348  	}
   349  }
   350  
   351  func getCausetRows(planStr string) []string {
   352  	planStr = strings.Replace(planStr, "\t", " ", -1)
   353  	return strings.Split(planStr, "\n")
   354  }
   355  
   356  func compareStringSlice(c *C, ss1, ss2 []string) {
   357  	c.Assert(len(ss1), Equals, len(ss2))
   358  	for i, s := range ss1 {
   359  		c.Assert(s, Equals, ss2[i])
   360  	}
   361  }
   362  
   363  func (s *testCausetNormalize) TestNthCausetHint(c *C) {
   364  	tk := testkit.NewTestKit(c, s.causetstore)
   365  	tk.MustInterDirc("use test")
   366  	tk.MustInterDirc("drop causet if exists tt")
   367  	tk.MustInterDirc("create causet tt (a int,b int, index(a), index(b));")
   368  	tk.MustInterDirc("insert into tt values (1, 1), (2, 2), (3, 4)")
   369  
   370  	tk.MustInterDirc("explain select /*+nth_plan(4)*/ * from tt where a=1 and b=1;")
   371  	tk.MustQuery("show warnings").Check(testkit.Rows(
   372  		"Warning 1105 The parameter of nth_plan() is out of range."))
   373  
   374  	// Test hints for nth_plan(x).
   375  	tk.MustInterDirc("drop causet if exists t")
   376  	tk.MustInterDirc("create causet t (a int, b int, c int, index(a), index(b), index(a,b))")
   377  	tk.MustQuery("explain format='hint' select * from t where a=1 and b=1").Check(testkit.Rows(
   378  		"use_index(@`sel_1` `test`.`t` `a_2`)"))
   379  	tk.MustQuery("explain format='hint' select /*+ nth_plan(1) */ * from t where a=1 and b=1").Check(testkit.Rows(
   380  		"use_index(@`sel_1` `test`.`t` ), nth_plan(1)"))
   381  	tk.MustQuery("explain format='hint' select /*+ nth_plan(2) */ * from t where a=1 and b=1").Check(testkit.Rows(
   382  		"use_index(@`sel_1` `test`.`t` `a_2`), nth_plan(2)"))
   383  
   384  	tk.MustInterDirc("explain format='hint' select /*+ nth_plan(3) */ * from t where a=1 and b=1")
   385  	tk.MustQuery("show warnings").Check(testkit.Rows(
   386  		"Warning 1105 The parameter of nth_plan() is out of range."))
   387  
   388  	tk.MustInterDirc("explain format='hint' select /*+ nth_plan(500) */ * from t where a=1 and b=1")
   389  	tk.MustQuery("show warnings").Check(testkit.Rows(
   390  		"Warning 1105 The parameter of nth_plan() is out of range."))
   391  
   392  	// Test warning for multiply hints.
   393  	tk.MustQuery("explain format='hint' select /*+ nth_plan(1) nth_plan(2) */ * from t where a=1 and b=1").Check(testkit.Rows(
   394  		"use_index(@`sel_1` `test`.`t` `a_2`), nth_plan(1), nth_plan(2)"))
   395  	tk.MustQuery("show warnings").Check(testkit.Rows(
   396  		"Warning 1105 NTH_PLAN() is defined more than once, only the last definition takes effect: NTH_PLAN(2)",
   397  		"Warning 1105 NTH_PLAN() is defined more than once, only the last definition takes effect: NTH_PLAN(2)"))
   398  
   399  	// Test the correctness of generated plans.
   400  	tk.MustInterDirc("insert into t values (1,1,1)")
   401  	tk.MustQuery("select  /*+ nth_plan(1) */ * from t where a=1 and b=1;").Check(testkit.Rows(
   402  		"1 1 1"))
   403  	tk.MustQuery("select  /*+ nth_plan(2) */ * from t where a=1 and b=1;").Check(testkit.Rows(
   404  		"1 1 1"))
   405  	tk.MustQuery("select  /*+ nth_plan(1) */ * from tt where a=1 and b=1;").Check(testkit.Rows(
   406  		"1 1"))
   407  	tk.MustQuery("select  /*+ nth_plan(2) */ * from tt where a=1 and b=1;").Check(testkit.Rows(
   408  		"1 1"))
   409  	tk.MustQuery("select  /*+ nth_plan(3) */ * from tt where a=1 and b=1;").Check(testkit.Rows(
   410  		"1 1"))
   411  
   412  	// Make sure nth_plan() doesn't affect separately executed subqueries by asserting there's only one warning.
   413  	tk.MustInterDirc("select /*+ nth_plan(1000) */ count(1) from t where (select count(1) from t, tt) > 1;")
   414  	tk.MustQuery("show warnings").Check(testkit.Rows(
   415  		"Warning 1105 The parameter of nth_plan() is out of range."))
   416  	tk.MustInterDirc("select /*+ nth_plan(1000) */ count(1) from t where exists (select count(1) from t, tt);")
   417  	tk.MustQuery("show warnings").Check(testkit.Rows(
   418  		"Warning 1105 The parameter of nth_plan() is out of range."))
   419  }
   420  
   421  func (s *testCausetNormalize) TestDecodeCausetPerformance(c *C) {
   422  	tk := testkit.NewTestKit(c, s.causetstore)
   423  	tk.MustInterDirc("use test")
   424  	tk.MustInterDirc("drop causet if exists t")
   425  	tk.MustInterDirc("create causet t (a varchar(10) key,b int);")
   426  	tk.MustInterDirc("set @@milevadb_slow_log_threshold=200000")
   427  
   428  	// generate ALLEGROALLEGROSQL
   429  	buf := bytes.NewBuffer(make([]byte, 0, 1024*1024*4))
   430  	for i := 0; i < 50000; i++ {
   431  		if i > 0 {
   432  			buf.WriteString(" union ")
   433  		}
   434  		buf.WriteString(fmt.Sprintf("select count(1) as num,a from t where a='%v' group by a", i))
   435  	}
   436  	query := buf.String()
   437  	tk.Se.GetStochastikVars().CausetID = 0
   438  	tk.MustInterDirc(query)
   439  	info := tk.Se.ShowProcess()
   440  	c.Assert(info, NotNil)
   441  	p, ok := info.Causet.(embedded.PhysicalCauset)
   442  	c.Assert(ok, IsTrue)
   443  	// TODO: optimize the encode plan performance when encode plan with runtimeStats
   444  	tk.Se.GetStochastikVars().StmtCtx.RuntimeStatsDefCausl = nil
   445  	encodedCausetStr := embedded.EncodeCauset(p)
   446  	start := time.Now()
   447  	_, err := plancodec.DecodeCauset(encodedCausetStr)
   448  	c.Assert(err, IsNil)
   449  	c.Assert(time.Since(start).Seconds(), Less, 3.0)
   450  }