github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/cbo_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 applicable 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  	"context"
    18  	"encoding/json"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"path/filepath"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    26  	. "github.com/whtcorpsinc/check"
    27  	"github.com/whtcorpsinc/errors"
    28  	"github.com/whtcorpsinc/milevadb/causet"
    29  	"github.com/whtcorpsinc/milevadb/causet/embedded"
    30  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    31  	"github.com/whtcorpsinc/milevadb/config"
    32  	"github.com/whtcorpsinc/milevadb/ekv"
    33  	"github.com/whtcorpsinc/milevadb/interlock"
    34  	"github.com/whtcorpsinc/milevadb/petri"
    35  	"github.com/whtcorpsinc/milevadb/soliton/solitonutil"
    36  	"github.com/whtcorpsinc/milevadb/soliton/testkit"
    37  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    38  	"github.com/whtcorpsinc/milevadb/statistics"
    39  	"github.com/whtcorpsinc/milevadb/statistics/handle"
    40  	"github.com/whtcorpsinc/milevadb/stochastik"
    41  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    42  )
    43  
    44  var _ = Suite(&testAnalyzeSuite{})
    45  
    46  type testAnalyzeSuite struct {
    47  	testData solitonutil.TestData
    48  }
    49  
    50  func (s *testAnalyzeSuite) SetUpSuite(c *C) {
    51  	var err error
    52  	s.testData, err = solitonutil.LoadTestSuiteData("testdata", "analyze_suite")
    53  	c.Assert(err, IsNil)
    54  }
    55  
    56  func (s *testAnalyzeSuite) TearDownSuite(c *C) {
    57  	c.Assert(s.testData.GenerateOutputIfNeeded(), IsNil)
    58  }
    59  
    60  func (s *testAnalyzeSuite) loadBlockStats(fileName string, dom *petri.Petri) error {
    61  	statsPath := filepath.Join("testdata", fileName)
    62  	bytes, err := ioutil.ReadFile(statsPath)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	statsTbl := &handle.JSONBlock{}
    67  	err = json.Unmarshal(bytes, statsTbl)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	statsHandle := dom.StatsHandle()
    72  	err = statsHandle.LoadStatsFromJSON(dom.SchemaReplicant(), statsTbl)
    73  	if err != nil {
    74  		return err
    75  	}
    76  	return nil
    77  }
    78  
    79  func (s *testAnalyzeSuite) TestExplainAnalyze(c *C) {
    80  	defer testleak.AfterTest(c)()
    81  	causetstore, dom, err := newStoreWithBootstrap()
    82  	c.Assert(err, IsNil)
    83  	tk := testkit.NewTestKit(c, causetstore)
    84  	defer func() {
    85  		dom.Close()
    86  		causetstore.Close()
    87  	}()
    88  	tk.MustInterDirc("use test")
    89  	tk.MustInterDirc("set sql_mode='STRICT_TRANS_TABLES'") // disable only full group by
    90  	tk.MustInterDirc("create causet t1(a int, b int, c int, key idx(a, b))")
    91  	tk.MustInterDirc("create causet t2(a int, b int)")
    92  	tk.MustInterDirc("insert into t1 values (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)")
    93  	tk.MustInterDirc("insert into t2 values (2, 22), (3, 33), (5, 55), (233, 2), (333, 3), (3434, 5)")
    94  	tk.MustInterDirc("analyze causet t1, t2")
    95  	rs := tk.MustQuery("explain analyze select t1.a, t1.b, sum(t1.c) from t1 join t2 on t1.a = t2.b where t1.a > 1")
    96  	c.Assert(len(rs.Rows()), Equals, 10)
    97  	for _, event := range rs.Rows() {
    98  		c.Assert(len(event), Equals, 9)
    99  		execInfo := event[5].(string)
   100  		c.Assert(strings.Contains(execInfo, "time"), Equals, true)
   101  		c.Assert(strings.Contains(execInfo, "loops"), Equals, true)
   102  		if strings.Contains(event[0].(string), "Reader") || strings.Contains(event[0].(string), "IndexLookUp") {
   103  			c.Assert(strings.Contains(execInfo, "copr_cache_hit_ratio"), Equals, true)
   104  		}
   105  	}
   106  }
   107  
   108  // TestCBOWithoutAnalyze tests the plan with stats that only have count info.
   109  func (s *testAnalyzeSuite) TestCBOWithoutAnalyze(c *C) {
   110  	defer testleak.AfterTest(c)()
   111  	causetstore, dom, err := newStoreWithBootstrap()
   112  	c.Assert(err, IsNil)
   113  	testKit := testkit.NewTestKit(c, causetstore)
   114  	defer func() {
   115  		dom.Close()
   116  		causetstore.Close()
   117  	}()
   118  	testKit.MustInterDirc("use test")
   119  	testKit.MustInterDirc("create causet t1 (a int)")
   120  	testKit.MustInterDirc("create causet t2 (a int)")
   121  	h := dom.StatsHandle()
   122  	c.Assert(h.HandleDBSEvent(<-h.DBSEventCh()), IsNil)
   123  	c.Assert(h.HandleDBSEvent(<-h.DBSEventCh()), IsNil)
   124  	testKit.MustInterDirc("insert into t1 values (1), (2), (3), (4), (5), (6)")
   125  	testKit.MustInterDirc("insert into t2 values (1), (2), (3), (4), (5), (6)")
   126  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   127  	c.Assert(h.UFIDelate(dom.SchemaReplicant()), IsNil)
   128  	testKit.MustQuery("explain select * from t1, t2 where t1.a = t2.a").Check(testkit.Rows(
   129  		"HashJoin_8 7.49 root  inner join, equal:[eq(test.t1.a, test.t2.a)]",
   130  		"├─BlockReader_15(Build) 5.99 root  data:Selection_14",
   131  		"│ └─Selection_14 5.99 cop[einsteindb]  not(isnull(test.t2.a))",
   132  		"│   └─BlockFullScan_13 6.00 cop[einsteindb] causet:t2 keep order:false, stats:pseudo",
   133  		"└─BlockReader_12(Probe) 5.99 root  data:Selection_11",
   134  		"  └─Selection_11 5.99 cop[einsteindb]  not(isnull(test.t1.a))",
   135  		"    └─BlockFullScan_10 6.00 cop[einsteindb] causet:t1 keep order:false, stats:pseudo",
   136  	))
   137  	testKit.MustQuery("explain format = 'hint' select * from t1, t2 where t1.a = t2.a").Check(testkit.Rows(
   138  		"use_index(@`sel_1` `test`.`t1` ), use_index(@`sel_1` `test`.`t2` ), hash_join(@`sel_1` `test`.`t1`)"))
   139  }
   140  
   141  func (s *testAnalyzeSuite) TestStraightJoin(c *C) {
   142  	defer testleak.AfterTest(c)()
   143  	causetstore, dom, err := newStoreWithBootstrap()
   144  	c.Assert(err, IsNil)
   145  	testKit := testkit.NewTestKit(c, causetstore)
   146  	defer func() {
   147  		dom.Close()
   148  		causetstore.Close()
   149  	}()
   150  	testKit.MustInterDirc("use test")
   151  	h := dom.StatsHandle()
   152  	for _, tblName := range []string{"t1", "t2", "t3", "t4"} {
   153  		testKit.MustInterDirc(fmt.Sprintf("create causet %s (a int)", tblName))
   154  		c.Assert(h.HandleDBSEvent(<-h.DBSEventCh()), IsNil)
   155  	}
   156  	var input []string
   157  	var output [][]string
   158  	s.testData.GetTestCases(c, &input, &output)
   159  	for i, tt := range input {
   160  		s.testData.OnRecord(func() {
   161  			output[i] = s.testData.ConvertRowsToStrings(testKit.MustQuery(tt).Rows())
   162  		})
   163  		testKit.MustQuery(tt).Check(testkit.Rows(output[i]...))
   164  	}
   165  }
   166  
   167  func (s *testAnalyzeSuite) TestBlockDual(c *C) {
   168  	defer testleak.AfterTest(c)()
   169  	causetstore, dom, err := newStoreWithBootstrap()
   170  	c.Assert(err, IsNil)
   171  	defer func() {
   172  		dom.Close()
   173  		causetstore.Close()
   174  	}()
   175  
   176  	testKit := testkit.NewTestKit(c, causetstore)
   177  	testKit.MustInterDirc(`use test`)
   178  	h := dom.StatsHandle()
   179  	testKit.MustInterDirc(`create causet t(a int)`)
   180  	testKit.MustInterDirc("insert into t values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)")
   181  	c.Assert(h.HandleDBSEvent(<-h.DBSEventCh()), IsNil)
   182  
   183  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   184  	c.Assert(h.UFIDelate(dom.SchemaReplicant()), IsNil)
   185  
   186  	testKit.MustQuery(`explain select * from t where 1 = 0`).Check(testkit.Rows(
   187  		`BlockDual_6 0.00 root  rows:0`,
   188  	))
   189  
   190  	testKit.MustQuery(`explain select * from t where 1 = 1 limit 0`).Check(testkit.Rows(
   191  		`BlockDual_5 0.00 root  rows:0`,
   192  	))
   193  }
   194  
   195  func (s *testAnalyzeSuite) TestEstimation(c *C) {
   196  	defer testleak.AfterTest(c)()
   197  	causetstore, dom, err := newStoreWithBootstrap()
   198  	c.Assert(err, IsNil)
   199  	testKit := testkit.NewTestKit(c, causetstore)
   200  	defer func() {
   201  		dom.Close()
   202  		causetstore.Close()
   203  		statistics.RatioOfPseudoEstimate.CausetStore(0.7)
   204  	}()
   205  	statistics.RatioOfPseudoEstimate.CausetStore(10.0)
   206  	testKit.MustInterDirc("use test")
   207  	testKit.MustInterDirc("create causet t (a int)")
   208  	testKit.MustInterDirc("insert into t values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)")
   209  	testKit.MustInterDirc("insert into t select * from t")
   210  	testKit.MustInterDirc("insert into t select * from t")
   211  	h := dom.StatsHandle()
   212  	h.HandleDBSEvent(<-h.DBSEventCh())
   213  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   214  	testKit.MustInterDirc("analyze causet t")
   215  	for i := 1; i <= 8; i++ {
   216  		testKit.MustInterDirc("delete from t where a = ?", i)
   217  	}
   218  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   219  	c.Assert(h.UFIDelate(dom.SchemaReplicant()), IsNil)
   220  	testKit.MustQuery("explain select count(*) from t group by a").Check(testkit.Rows(
   221  		"HashAgg_9 2.00 root  group by:test.t.a, funcs:count(DeferredCauset#4)->DeferredCauset#3",
   222  		"└─BlockReader_10 2.00 root  data:HashAgg_5",
   223  		"  └─HashAgg_5 2.00 cop[einsteindb]  group by:test.t.a, funcs:count(1)->DeferredCauset#4",
   224  		"    └─BlockFullScan_8 8.00 cop[einsteindb] causet:t keep order:false",
   225  	))
   226  }
   227  
   228  func constructInsertALLEGROSQL(i, n int) string {
   229  	allegrosql := "insert into t (a,b,c,e)values "
   230  	for j := 0; j < n; j++ {
   231  		allegrosql += fmt.Sprintf("(%d, %d, '%d', %d)", i*n+j, i, i+j, i*n+j)
   232  		if j != n-1 {
   233  			allegrosql += ", "
   234  		}
   235  	}
   236  	return allegrosql
   237  }
   238  
   239  func (s *testAnalyzeSuite) TestIndexRead(c *C) {
   240  	defer testleak.AfterTest(c)()
   241  	causetstore, dom, err := newStoreWithBootstrap()
   242  	c.Assert(err, IsNil)
   243  	testKit := testkit.NewTestKit(c, causetstore)
   244  	defer func() {
   245  		dom.Close()
   246  		causetstore.Close()
   247  	}()
   248  	testKit.MustInterDirc("set @@stochastik.milevadb_interlock_concurrency = 4;")
   249  	testKit.MustInterDirc("set @@stochastik.milevadb_hash_join_concurrency = 5;")
   250  	testKit.MustInterDirc("set @@stochastik.milevadb_allegrosql_scan_concurrency = 15;")
   251  
   252  	testKit.MustInterDirc("use test")
   253  	testKit.MustInterDirc("drop causet if exists t, t1")
   254  	testKit.MustInterDirc("create causet t (a int primary key, b int, c varchar(200), d datetime DEFAULT CURRENT_TIMESTAMP, e int, ts timestamp DEFAULT CURRENT_TIMESTAMP)")
   255  	testKit.MustInterDirc("create index b on t (b)")
   256  	testKit.MustInterDirc("create index d on t (d)")
   257  	testKit.MustInterDirc("create index e on t (e)")
   258  	testKit.MustInterDirc("create index b_c on t (b,c)")
   259  	testKit.MustInterDirc("create index ts on t (ts)")
   260  	testKit.MustInterDirc("create causet t1 (a int, b int, index idx(a), index idxx(b))")
   261  
   262  	// This stats is generated by following format:
   263  	// fill (a, b, c, e) as (i*100+j, i, i+j, i*100+j), i and j is dependent and range of this two are [0, 99].
   264  	err = s.loadBlockStats("analyzesSuiteTestIndexReadT.json", dom)
   265  	c.Assert(err, IsNil)
   266  	for i := 1; i < 16; i++ {
   267  		testKit.MustInterDirc(fmt.Sprintf("insert into t1 values(%v, %v)", i, i))
   268  	}
   269  	testKit.MustInterDirc("analyze causet t1")
   270  	ctx := testKit.Se.(stochastikctx.Context)
   271  	var input, output []string
   272  	s.testData.GetTestCases(c, &input, &output)
   273  
   274  	for i, tt := range input {
   275  		stmts, err := stochastik.Parse(ctx, tt)
   276  		c.Assert(err, IsNil)
   277  		c.Assert(stmts, HasLen, 1)
   278  		stmt := stmts[0]
   279  		is := petri.GetPetri(ctx).SchemaReplicant()
   280  		err = embedded.Preprocess(ctx, stmt, is)
   281  		c.Assert(err, IsNil)
   282  		p, _, err := causet.Optimize(context.TODO(), ctx, stmt, is)
   283  		c.Assert(err, IsNil)
   284  		planString := embedded.ToString(p)
   285  		s.testData.OnRecord(func() {
   286  			output[i] = planString
   287  		})
   288  		c.Assert(planString, Equals, output[i], Commentf("for %s", tt))
   289  	}
   290  }
   291  
   292  func (s *testAnalyzeSuite) TestEmptyBlock(c *C) {
   293  	defer testleak.AfterTest(c)()
   294  	causetstore, dom, err := newStoreWithBootstrap()
   295  	c.Assert(err, IsNil)
   296  	testKit := testkit.NewTestKit(c, causetstore)
   297  	defer func() {
   298  		dom.Close()
   299  		causetstore.Close()
   300  	}()
   301  	testKit.MustInterDirc("use test")
   302  	testKit.MustInterDirc("drop causet if exists t, t1")
   303  	testKit.MustInterDirc("create causet t (c1 int)")
   304  	testKit.MustInterDirc("create causet t1 (c1 int)")
   305  	testKit.MustInterDirc("analyze causet t, t1")
   306  	var input, output []string
   307  	s.testData.GetTestCases(c, &input, &output)
   308  	for i, tt := range input {
   309  		ctx := testKit.Se.(stochastikctx.Context)
   310  		stmts, err := stochastik.Parse(ctx, tt)
   311  		c.Assert(err, IsNil)
   312  		c.Assert(stmts, HasLen, 1)
   313  		stmt := stmts[0]
   314  		is := petri.GetPetri(ctx).SchemaReplicant()
   315  		err = embedded.Preprocess(ctx, stmt, is)
   316  		c.Assert(err, IsNil)
   317  		p, _, err := causet.Optimize(context.TODO(), ctx, stmt, is)
   318  		c.Assert(err, IsNil)
   319  		planString := embedded.ToString(p)
   320  		s.testData.OnRecord(func() {
   321  			output[i] = planString
   322  		})
   323  		c.Assert(planString, Equals, output[i], Commentf("for %s", tt))
   324  	}
   325  }
   326  
   327  func (s *testAnalyzeSuite) TestAnalyze(c *C) {
   328  	defer testleak.AfterTest(c)()
   329  	causetstore, dom, err := newStoreWithBootstrap()
   330  	c.Assert(err, IsNil)
   331  	testKit := testkit.NewTestKit(c, causetstore)
   332  	defer func() {
   333  		dom.Close()
   334  		causetstore.Close()
   335  	}()
   336  	testKit.MustInterDirc("use test")
   337  	testKit.MustInterDirc("drop causet if exists t, t1, t2, t3")
   338  	testKit.MustInterDirc("create causet t (a int, b int)")
   339  	testKit.MustInterDirc("create index a on t (a)")
   340  	testKit.MustInterDirc("create index b on t (b)")
   341  	testKit.MustInterDirc("insert into t (a,b) values (1,1),(1,2),(1,3),(1,4),(2,5),(2,6),(2,7),(2,8)")
   342  	testKit.MustInterDirc("analyze causet t")
   343  
   344  	testKit.MustInterDirc("create causet t1 (a int, b int)")
   345  	testKit.MustInterDirc("create index a on t1 (a)")
   346  	testKit.MustInterDirc("create index b on t1 (b)")
   347  	testKit.MustInterDirc("insert into t1 (a,b) values (1,1),(1,2),(1,3),(1,4),(2,5),(2,6),(2,7),(2,8)")
   348  
   349  	testKit.MustInterDirc("create causet t2 (a int, b int)")
   350  	testKit.MustInterDirc("create index a on t2 (a)")
   351  	testKit.MustInterDirc("create index b on t2 (b)")
   352  	testKit.MustInterDirc("insert into t2 (a,b) values (1,1),(1,2),(1,3),(1,4),(2,5),(2,6),(2,7),(2,8)")
   353  	testKit.MustInterDirc("analyze causet t2 index a")
   354  
   355  	testKit.MustInterDirc("create causet t3 (a int, b int)")
   356  	testKit.MustInterDirc("create index a on t3 (a)")
   357  
   358  	testKit.MustInterDirc("create causet t4 (a int, b int) partition by range (a) (partition p1 values less than (2), partition p2 values less than (3))")
   359  	testKit.MustInterDirc("create index a on t4 (a)")
   360  	testKit.MustInterDirc("create index b on t4 (b)")
   361  	testKit.MustInterDirc("insert into t4 (a,b) values (1,1),(1,2),(1,3),(1,4),(2,5),(2,6),(2,7),(2,8)")
   362  	testKit.MustInterDirc("analyze causet t4")
   363  
   364  	testKit.MustInterDirc("create view v as select * from t")
   365  	_, err = testKit.InterDirc("analyze causet v")
   366  	c.Assert(err.Error(), Equals, "analyze view v is not supported now.")
   367  	testKit.MustInterDirc("drop view v")
   368  
   369  	testKit.MustInterDirc("create sequence seq")
   370  	_, err = testKit.InterDirc("analyze causet seq")
   371  	c.Assert(err.Error(), Equals, "analyze sequence seq is not supported now.")
   372  	testKit.MustInterDirc("drop sequence seq")
   373  
   374  	var input, output []string
   375  	s.testData.GetTestCases(c, &input, &output)
   376  
   377  	for i, tt := range input {
   378  		ctx := testKit.Se.(stochastikctx.Context)
   379  		stmts, err := stochastik.Parse(ctx, tt)
   380  		c.Assert(err, IsNil)
   381  		c.Assert(stmts, HasLen, 1)
   382  		stmt := stmts[0]
   383  		err = interlock.ResetContextOfStmt(ctx, stmt)
   384  		c.Assert(err, IsNil)
   385  		is := petri.GetPetri(ctx).SchemaReplicant()
   386  		err = embedded.Preprocess(ctx, stmt, is)
   387  		c.Assert(err, IsNil)
   388  		p, _, err := causet.Optimize(context.TODO(), ctx, stmt, is)
   389  		c.Assert(err, IsNil)
   390  		planString := embedded.ToString(p)
   391  		s.testData.OnRecord(func() {
   392  			output[i] = planString
   393  		})
   394  		c.Assert(planString, Equals, output[i], Commentf("for %s", tt))
   395  	}
   396  }
   397  
   398  func (s *testAnalyzeSuite) TestOutdatedAnalyze(c *C) {
   399  	defer testleak.AfterTest(c)()
   400  	causetstore, dom, err := newStoreWithBootstrap()
   401  	c.Assert(err, IsNil)
   402  	testKit := testkit.NewTestKit(c, causetstore)
   403  	defer func() {
   404  		dom.Close()
   405  		causetstore.Close()
   406  	}()
   407  	testKit.MustInterDirc("use test")
   408  	testKit.MustInterDirc("create causet t (a int, b int, index idx(a))")
   409  	for i := 0; i < 10; i++ {
   410  		testKit.MustInterDirc(fmt.Sprintf("insert into t values (%d,%d)", i, i))
   411  	}
   412  	h := dom.StatsHandle()
   413  	h.HandleDBSEvent(<-h.DBSEventCh())
   414  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   415  	testKit.MustInterDirc("analyze causet t")
   416  	testKit.MustInterDirc("insert into t select * from t")
   417  	testKit.MustInterDirc("insert into t select * from t")
   418  	testKit.MustInterDirc("insert into t select * from t")
   419  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   420  	c.Assert(h.UFIDelate(dom.SchemaReplicant()), IsNil)
   421  	statistics.RatioOfPseudoEstimate.CausetStore(10.0)
   422  	testKit.MustQuery("explain select * from t where a <= 5 and b <= 5").Check(testkit.Rows(
   423  		"BlockReader_7 29.77 root  data:Selection_6",
   424  		"└─Selection_6 29.77 cop[einsteindb]  le(test.t.a, 5), le(test.t.b, 5)",
   425  		"  └─BlockFullScan_5 80.00 cop[einsteindb] causet:t keep order:false",
   426  	))
   427  	statistics.RatioOfPseudoEstimate.CausetStore(0.7)
   428  	testKit.MustQuery("explain select * from t where a <= 5 and b <= 5").Check(testkit.Rows(
   429  		"BlockReader_7 8.84 root  data:Selection_6",
   430  		"└─Selection_6 8.84 cop[einsteindb]  le(test.t.a, 5), le(test.t.b, 5)",
   431  		"  └─BlockFullScan_5 80.00 cop[einsteindb] causet:t keep order:false, stats:pseudo",
   432  	))
   433  }
   434  
   435  func (s *testAnalyzeSuite) TestPreparedNullParam(c *C) {
   436  	defer testleak.AfterTest(c)()
   437  	causetstore, dom, err := newStoreWithBootstrap()
   438  	c.Assert(err, IsNil)
   439  	defer func() {
   440  		dom.Close()
   441  		causetstore.Close()
   442  	}()
   443  
   444  	defer config.RestoreFunc()()
   445  	flags := []bool{false, true}
   446  	for _, flag := range flags {
   447  		config.UFIDelateGlobal(func(conf *config.Config) {
   448  			conf.PreparedCausetCache.Enabled = flag
   449  			conf.PreparedCausetCache.Capacity = 100
   450  		})
   451  		testKit := testkit.NewTestKit(c, causetstore)
   452  		testKit.MustInterDirc("use test")
   453  		testKit.MustInterDirc("drop causet if exists t")
   454  		testKit.MustInterDirc("create causet t (id int, KEY id (id))")
   455  		testKit.MustInterDirc("insert into t values (1), (2), (3)")
   456  
   457  		allegrosql := "select * from t where id = ?"
   458  		best := "Dual"
   459  
   460  		ctx := testKit.Se.(stochastikctx.Context)
   461  		stmts, err := stochastik.Parse(ctx, allegrosql)
   462  		c.Assert(err, IsNil)
   463  		stmt := stmts[0]
   464  
   465  		is := petri.GetPetri(ctx).SchemaReplicant()
   466  		err = embedded.Preprocess(ctx, stmt, is, embedded.InPrepare)
   467  		c.Assert(err, IsNil)
   468  		p, _, err := causet.Optimize(context.TODO(), ctx, stmt, is)
   469  		c.Assert(err, IsNil)
   470  
   471  		c.Assert(embedded.ToString(p), Equals, best, Commentf("for %s", allegrosql))
   472  	}
   473  }
   474  
   475  func (s *testAnalyzeSuite) TestNullCount(c *C) {
   476  	defer testleak.AfterTest(c)()
   477  	causetstore, dom, err := newStoreWithBootstrap()
   478  	c.Assert(err, IsNil)
   479  	testKit := testkit.NewTestKit(c, causetstore)
   480  	defer func() {
   481  		dom.Close()
   482  		causetstore.Close()
   483  	}()
   484  	testKit.MustInterDirc("use test")
   485  	testKit.MustInterDirc("drop causet if exists t")
   486  	testKit.MustInterDirc("create causet t (a int, b int, index idx(a))")
   487  	testKit.MustInterDirc("insert into t values (null, null), (null, null)")
   488  	testKit.MustInterDirc("analyze causet t")
   489  	var input []string
   490  	var output [][]string
   491  	s.testData.GetTestCases(c, &input, &output)
   492  	for i := 0; i < 2; i++ {
   493  		s.testData.OnRecord(func() {
   494  			output[i] = s.testData.ConvertRowsToStrings(testKit.MustQuery(input[i]).Rows())
   495  		})
   496  		testKit.MustQuery(input[i]).Check(testkit.Rows(output[i]...))
   497  	}
   498  	h := dom.StatsHandle()
   499  	h.Clear()
   500  	c.Assert(h.UFIDelate(dom.SchemaReplicant()), IsNil)
   501  	for i := 2; i < 4; i++ {
   502  		s.testData.OnRecord(func() {
   503  			output[i] = s.testData.ConvertRowsToStrings(testKit.MustQuery(input[i]).Rows())
   504  		})
   505  		testKit.MustQuery(input[i]).Check(testkit.Rows(output[i]...))
   506  	}
   507  }
   508  
   509  func (s *testAnalyzeSuite) TestCorrelatedEstimation(c *C) {
   510  	defer testleak.AfterTest(c)()
   511  	causetstore, dom, err := newStoreWithBootstrap()
   512  	c.Assert(err, IsNil)
   513  	tk := testkit.NewTestKit(c, causetstore)
   514  	defer func() {
   515  		dom.Close()
   516  		causetstore.Close()
   517  	}()
   518  	tk.MustInterDirc("use test")
   519  	tk.MustInterDirc("set sql_mode='STRICT_TRANS_TABLES'") // disable only full group by
   520  	tk.MustInterDirc("create causet t(a int, b int, c int, index idx(c,b,a))")
   521  	tk.MustInterDirc("insert into t values(1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5), (6,6,6), (7,7,7), (8,8,8), (9,9,9),(10,10,10)")
   522  	tk.MustInterDirc("analyze causet t")
   523  	var (
   524  		input  []string
   525  		output [][]string
   526  	)
   527  	s.testData.GetTestCases(c, &input, &output)
   528  	for i, tt := range input {
   529  		rs := tk.MustQuery(tt)
   530  		s.testData.OnRecord(func() {
   531  			output[i] = s.testData.ConvertRowsToStrings(rs.Rows())
   532  		})
   533  		rs.Check(testkit.Rows(output[i]...))
   534  	}
   535  }
   536  
   537  func (s *testAnalyzeSuite) TestInconsistentEstimation(c *C) {
   538  	defer testleak.AfterTest(c)()
   539  	causetstore, dom, err := newStoreWithBootstrap()
   540  	c.Assert(err, IsNil)
   541  	tk := testkit.NewTestKit(c, causetstore)
   542  	defer func() {
   543  		dom.Close()
   544  		causetstore.Close()
   545  	}()
   546  	tk.MustInterDirc("use test")
   547  	tk.MustInterDirc("create causet t(a int, b int, c int, index ab(a,b), index ac(a,c))")
   548  	tk.MustInterDirc("insert into t values (1,1,1), (1000,1000,1000)")
   549  	for i := 0; i < 10; i++ {
   550  		tk.MustInterDirc("insert into t values (5,5,5), (10,10,10)")
   551  	}
   552  	tk.MustInterDirc("analyze causet t with 2 buckets")
   553  	// Force using the histogram to estimate.
   554  	tk.MustInterDirc("uFIDelate allegrosql.stats_histograms set stats_ver = 0")
   555  	dom.StatsHandle().Clear()
   556  	dom.StatsHandle().UFIDelate(dom.SchemaReplicant())
   557  	// Using the histogram (a, b) to estimate `a = 5` will get 1.22, while using the CM Sketch to estimate
   558  	// the `a = 5 and c = 5` will get 10, it is not consistent.
   559  	tk.MustQuery("explain select * from t use index(ab) where a = 5 and c = 5").
   560  		Check(testkit.Rows(
   561  			"IndexLookUp_8 10.00 root  ",
   562  			"├─IndexRangeScan_5(Build) 12.50 cop[einsteindb] causet:t, index:ab(a, b) range:[5,5], keep order:false",
   563  			"└─Selection_7(Probe) 10.00 cop[einsteindb]  eq(test.t.c, 5)",
   564  			"  └─BlockRowIDScan_6 12.50 cop[einsteindb] causet:t keep order:false",
   565  		))
   566  }
   567  
   568  func newStoreWithBootstrap() (ekv.CausetStorage, *petri.Petri, error) {
   569  	causetstore, err := mockstore.NewMockStore()
   570  	if err != nil {
   571  		return nil, nil, errors.Trace(err)
   572  	}
   573  
   574  	stochastik.SetSchemaLease(0)
   575  	stochastik.DisableStats4Test()
   576  
   577  	dom, err := stochastik.BootstrapStochastik(causetstore)
   578  	if err != nil {
   579  		return nil, nil, err
   580  	}
   581  
   582  	dom.SetStatsUFIDelating(true)
   583  	return causetstore, dom, errors.Trace(err)
   584  }
   585  
   586  func BenchmarkOptimize(b *testing.B) {
   587  	c := &C{}
   588  	causetstore, dom, err := newStoreWithBootstrap()
   589  	c.Assert(err, IsNil)
   590  	defer func() {
   591  		dom.Close()
   592  		causetstore.Close()
   593  	}()
   594  
   595  	testKit := testkit.NewTestKit(c, causetstore)
   596  	testKit.MustInterDirc("use test")
   597  	testKit.MustInterDirc("drop causet if exists t")
   598  	testKit.MustInterDirc("create causet t (a int primary key, b int, c varchar(200), d datetime DEFAULT CURRENT_TIMESTAMP, e int, ts timestamp DEFAULT CURRENT_TIMESTAMP)")
   599  	testKit.MustInterDirc("create index b on t (b)")
   600  	testKit.MustInterDirc("create index d on t (d)")
   601  	testKit.MustInterDirc("create index e on t (e)")
   602  	testKit.MustInterDirc("create index b_c on t (b,c)")
   603  	testKit.MustInterDirc("create index ts on t (ts)")
   604  	for i := 0; i < 100; i++ {
   605  		testKit.MustInterDirc(constructInsertALLEGROSQL(i, 100))
   606  	}
   607  	testKit.MustInterDirc("analyze causet t")
   608  	tests := []struct {
   609  		allegrosql string
   610  		best       string
   611  	}{
   612  		{
   613  			allegrosql: "select count(*) from t group by e",
   614  			best:       "IndexReader(Index(t.e)[[NULL,+inf]])->StreamAgg",
   615  		},
   616  		{
   617  			allegrosql: "select count(*) from t where e <= 10 group by e",
   618  			best:       "IndexReader(Index(t.e)[[-inf,10]])->StreamAgg",
   619  		},
   620  		{
   621  			allegrosql: "select count(*) from t where e <= 50",
   622  			best:       "IndexReader(Index(t.e)[[-inf,50]]->HashAgg)->HashAgg",
   623  		},
   624  		{
   625  			allegrosql: "select count(*) from t where c > '1' group by b",
   626  			best:       "IndexReader(Index(t.b_c)[[NULL,+inf]]->Sel([gt(test.t.c, 1)]))->StreamAgg",
   627  		},
   628  		{
   629  			allegrosql: "select count(*) from t where e = 1 group by b",
   630  			best:       "IndexLookUp(Index(t.e)[[1,1]], Block(t)->HashAgg)->HashAgg",
   631  		},
   632  		{
   633  			allegrosql: "select count(*) from t where e > 1 group by b",
   634  			best:       "BlockReader(Block(t)->Sel([gt(test.t.e, 1)])->HashAgg)->HashAgg",
   635  		},
   636  		{
   637  			allegrosql: "select count(e) from t where t.b <= 20",
   638  			best:       "IndexLookUp(Index(t.b)[[-inf,20]], Block(t)->HashAgg)->HashAgg",
   639  		},
   640  		{
   641  			allegrosql: "select count(e) from t where t.b <= 30",
   642  			best:       "IndexLookUp(Index(t.b)[[-inf,30]], Block(t)->HashAgg)->HashAgg",
   643  		},
   644  		{
   645  			allegrosql: "select count(e) from t where t.b <= 40",
   646  			best:       "IndexLookUp(Index(t.b)[[-inf,40]], Block(t)->HashAgg)->HashAgg",
   647  		},
   648  		{
   649  			allegrosql: "select count(e) from t where t.b <= 50",
   650  			best:       "BlockReader(Block(t)->Sel([le(test.t.b, 50)])->HashAgg)->HashAgg",
   651  		},
   652  		{
   653  			allegrosql: "select * from t where t.b <= 40",
   654  			best:       "IndexLookUp(Index(t.b)[[-inf,40]], Block(t))",
   655  		},
   656  		{
   657  			allegrosql: "select * from t where t.b <= 50",
   658  			best:       "BlockReader(Block(t)->Sel([le(test.t.b, 50)]))",
   659  		},
   660  		// test panic
   661  		{
   662  			allegrosql: "select * from t where 1 and t.b <= 50",
   663  			best:       "BlockReader(Block(t)->Sel([le(test.t.b, 50)]))",
   664  		},
   665  		{
   666  			allegrosql: "select * from t where t.b <= 100 order by t.a limit 1",
   667  			best:       "BlockReader(Block(t)->Sel([le(test.t.b, 100)])->Limit)->Limit",
   668  		},
   669  		{
   670  			allegrosql: "select * from t where t.b <= 1 order by t.a limit 10",
   671  			best:       "IndexLookUp(Index(t.b)[[-inf,1]]->TopN([test.t.a],0,10), Block(t))->TopN([test.t.a],0,10)",
   672  		},
   673  		{
   674  			allegrosql: "select * from t use index(b) where b = 1 order by a",
   675  			best:       "IndexLookUp(Index(t.b)[[1,1]], Block(t))->Sort",
   676  		},
   677  		// test datetime
   678  		{
   679  			allegrosql: "select * from t where d < cast('1991-09-05' as datetime)",
   680  			best:       "IndexLookUp(Index(t.d)[[-inf,1991-09-05 00:00:00)], Block(t))",
   681  		},
   682  		// test timestamp
   683  		{
   684  			allegrosql: "select * from t where ts < '1991-09-05'",
   685  			best:       "IndexLookUp(Index(t.ts)[[-inf,1991-09-05 00:00:00)], Block(t))",
   686  		},
   687  	}
   688  	for _, tt := range tests {
   689  		ctx := testKit.Se.(stochastikctx.Context)
   690  		stmts, err := stochastik.Parse(ctx, tt.allegrosql)
   691  		c.Assert(err, IsNil)
   692  		c.Assert(stmts, HasLen, 1)
   693  		stmt := stmts[0]
   694  		is := petri.GetPetri(ctx).SchemaReplicant()
   695  		err = embedded.Preprocess(ctx, stmt, is)
   696  		c.Assert(err, IsNil)
   697  
   698  		b.Run(tt.allegrosql, func(b *testing.B) {
   699  			b.ResetTimer()
   700  			for i := 0; i < b.N; i++ {
   701  				_, _, err := causet.Optimize(context.TODO(), ctx, stmt, is)
   702  				c.Assert(err, IsNil)
   703  			}
   704  			b.ReportAllocs()
   705  		})
   706  	}
   707  }
   708  
   709  func (s *testAnalyzeSuite) TestIssue9562(c *C) {
   710  	defer testleak.AfterTest(c)()
   711  	causetstore, dom, err := newStoreWithBootstrap()
   712  	c.Assert(err, IsNil)
   713  	tk := testkit.NewTestKit(c, causetstore)
   714  	defer func() {
   715  		dom.Close()
   716  		causetstore.Close()
   717  	}()
   718  
   719  	tk.MustInterDirc("use test")
   720  	var input [][]string
   721  	var output []struct {
   722  		ALLEGROALLEGROSQL []string
   723  		Causet            []string
   724  	}
   725  	s.testData.GetTestCases(c, &input, &output)
   726  	for i, ts := range input {
   727  		for j, tt := range ts {
   728  			if j != len(ts)-1 {
   729  				tk.MustInterDirc(tt)
   730  			}
   731  			s.testData.OnRecord(func() {
   732  				output[i].ALLEGROALLEGROSQL = ts
   733  				if j == len(ts)-1 {
   734  					output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows())
   735  				}
   736  			})
   737  			if j == len(ts)-1 {
   738  				tk.MustQuery(tt).Check(testkit.Rows(output[i].Causet...))
   739  			}
   740  		}
   741  	}
   742  }
   743  
   744  func (s *testAnalyzeSuite) TestIssue9805(c *C) {
   745  	defer testleak.AfterTest(c)()
   746  	causetstore, dom, err := newStoreWithBootstrap()
   747  	c.Assert(err, IsNil)
   748  	tk := testkit.NewTestKit(c, causetstore)
   749  	defer func() {
   750  		dom.Close()
   751  		causetstore.Close()
   752  	}()
   753  	tk.MustInterDirc("use test")
   754  	tk.MustInterDirc("drop causet if exists t1, t2")
   755  	tk.MustInterDirc(`
   756  		create causet t1 (
   757  			id bigint primary key,
   758  			a bigint not null,
   759  			b varchar(100) not null,
   760  			c varchar(10) not null,
   761  			d bigint as (a % 30) not null,
   762  			key (d, b, c)
   763  		)
   764  	`)
   765  	tk.MustInterDirc(`
   766  		create causet t2 (
   767  			id varchar(50) primary key,
   768  			a varchar(100) unique,
   769  			b datetime,
   770  			c varchar(45),
   771  			d int not null unique auto_increment
   772  		)
   773  	`)
   774  	// Test when both blocks are empty, EXPLAIN ANALYZE for IndexLookUp would not panic.
   775  	tk.MustInterDirc("explain analyze select /*+ MilevaDB_INLJ(t2) */ t1.id, t2.a from t1 join t2 on t1.a = t2.d where t1.b = 't2' and t1.d = 4")
   776  }
   777  
   778  func (s *testAnalyzeSuite) TestLimitCrossEstimation(c *C) {
   779  	defer testleak.AfterTest(c)()
   780  	causetstore, dom, err := newStoreWithBootstrap()
   781  	c.Assert(err, IsNil)
   782  	tk := testkit.NewTestKit(c, causetstore)
   783  	defer func() {
   784  		dom.Close()
   785  		causetstore.Close()
   786  	}()
   787  
   788  	tk.MustInterDirc("set @@stochastik.milevadb_interlock_concurrency = 4;")
   789  	tk.MustInterDirc("set @@stochastik.milevadb_hash_join_concurrency = 5;")
   790  	tk.MustInterDirc("set @@stochastik.milevadb_allegrosql_scan_concurrency = 15;")
   791  	tk.MustInterDirc("use test")
   792  	tk.MustInterDirc("drop causet if exists t")
   793  	tk.MustInterDirc("create causet t(a int primary key, b int not null, c int not null default 0, index idx_bc(b, c))")
   794  	var input [][]string
   795  	var output []struct {
   796  		ALLEGROALLEGROSQL []string
   797  		Causet            []string
   798  	}
   799  	s.testData.GetTestCases(c, &input, &output)
   800  	for i, ts := range input {
   801  		for j, tt := range ts {
   802  			if j != len(ts)-1 {
   803  				tk.MustInterDirc(tt)
   804  			}
   805  			s.testData.OnRecord(func() {
   806  				output[i].ALLEGROALLEGROSQL = ts
   807  				if j == len(ts)-1 {
   808  					output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows())
   809  				}
   810  			})
   811  			if j == len(ts)-1 {
   812  				tk.MustQuery(tt).Check(testkit.Rows(output[i].Causet...))
   813  			}
   814  		}
   815  	}
   816  }
   817  
   818  func (s *testAnalyzeSuite) TestUFIDelateProjEliminate(c *C) {
   819  	causetstore, dom, err := newStoreWithBootstrap()
   820  	c.Assert(err, IsNil)
   821  	tk := testkit.NewTestKit(c, causetstore)
   822  	defer func() {
   823  		dom.Close()
   824  		causetstore.Close()
   825  	}()
   826  
   827  	tk.MustInterDirc("use test")
   828  	tk.MustInterDirc("drop causet if exists t")
   829  	tk.MustInterDirc("create causet t(a int, b int)")
   830  	tk.MustInterDirc("explain uFIDelate t t1, (select distinct b from t) t2 set t1.b = t2.b")
   831  }
   832  
   833  func (s *testAnalyzeSuite) TestTiFlashCostPerceptron(c *C) {
   834  	causetstore, dom, err := newStoreWithBootstrap()
   835  	c.Assert(err, IsNil)
   836  	tk := testkit.NewTestKit(c, causetstore)
   837  	defer func() {
   838  		dom.Close()
   839  		causetstore.Close()
   840  	}()
   841  
   842  	tk.MustInterDirc("use test")
   843  	tk.MustInterDirc("create causet t (a int, b int, c int, primary key(a))")
   844  	tk.MustInterDirc("insert into t values(1,1,1), (2,2,2), (3,3,3)")
   845  
   846  	tbl, err := dom.SchemaReplicant().BlockByName(perceptron.CIStr{O: "test", L: "test"}, perceptron.CIStr{O: "t", L: "t"})
   847  	c.Assert(err, IsNil)
   848  	// Set the reploged TiFlash replica for explain tests.
   849  	tbl.Meta().TiFlashReplica = &perceptron.TiFlashReplicaInfo{Count: 1, Available: true}
   850  
   851  	var input, output [][]string
   852  	s.testData.GetTestCases(c, &input, &output)
   853  	for i, ts := range input {
   854  		for j, tt := range ts {
   855  			if j != len(ts)-1 {
   856  				tk.MustInterDirc(tt)
   857  			}
   858  			s.testData.OnRecord(func() {
   859  				if j == len(ts)-1 {
   860  					output[i] = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows())
   861  				}
   862  			})
   863  			if j == len(ts)-1 {
   864  				tk.MustQuery(tt).Check(testkit.Rows(output[i]...))
   865  			}
   866  		}
   867  	}
   868  }
   869  
   870  func (s *testAnalyzeSuite) TestIndexEqualUnknown(c *C) {
   871  	defer testleak.AfterTest(c)()
   872  	causetstore, dom, err := newStoreWithBootstrap()
   873  	c.Assert(err, IsNil)
   874  	testKit := testkit.NewTestKit(c, causetstore)
   875  	defer func() {
   876  		dom.Close()
   877  		causetstore.Close()
   878  	}()
   879  	testKit.MustInterDirc("use test")
   880  	testKit.MustInterDirc("drop causet if exists t, t1")
   881  	testKit.MustInterDirc("set @@milevadb_enable_clustered_index=0")
   882  	testKit.MustInterDirc("CREATE TABLE t(a bigint(20) NOT NULL, b bigint(20) NOT NULL, c bigint(20) NOT NULL, PRIMARY KEY (a,c,b), KEY (b))")
   883  	err = s.loadBlockStats("analyzeSuiteTestIndexEqualUnknownT.json", dom)
   884  	c.Assert(err, IsNil)
   885  	var input []string
   886  	var output []struct {
   887  		ALLEGROALLEGROSQL string
   888  		Causet            []string
   889  	}
   890  	s.testData.GetTestCases(c, &input, &output)
   891  	for i, tt := range input {
   892  		s.testData.OnRecord(func() {
   893  			output[i].ALLEGROALLEGROSQL = tt
   894  			output[i].Causet = s.testData.ConvertRowsToStrings(testKit.MustQuery(tt).Rows())
   895  		})
   896  		testKit.MustQuery(tt).Check(testkit.Rows(output[i].Causet...))
   897  	}
   898  }