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 }