Skip to content

Commit

Permalink
planner: generate addition selection when plan cache enable (pingcap#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Reminiscent authored Sep 29, 2021
1 parent 8c357a1 commit 091ae3b
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 20 deletions.
215 changes: 210 additions & 5 deletions executor/explainfor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,14 +557,219 @@ func (s *testPrepareSerialSuite) TestExpressionIndexPreparePlanCache(c *C) {
ps := []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res := tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[2][3], Matches, ".*expression_index.*")
c.Assert(res.Rows()[2][4], Matches, ".*[123,123].*")
c.Assert(len(res.Rows()), Equals, 5)
c.Assert(res.Rows()[3][3], Matches, ".*expression_index.*")
c.Assert(res.Rows()[3][4], Matches, ".*[123,123].*")

tk.MustExec("set @a = 1234")
tk.MustExec("execute stmt using @a")
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 5)
c.Assert(res.Rows()[3][3], Matches, ".*expression_index.*")
c.Assert(res.Rows()[3][4], Matches, ".*[1234,1234].*")
}

func (s *testPrepareSerialSuite) TestIssue28259(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)

orgEnable := core.PreparedPlanCacheEnabled()
defer func() {
core.SetPreparedPlanCache(orgEnable)
}()
core.SetPreparedPlanCache(true)

var err error
tk.Se, err = session.CreateSession4TestWithOpt(s.store, &session.Opt{
PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64),
})
c.Assert(err, IsNil)

// test for indexRange
tk.MustExec("use test")
tk.MustExec("set @@tidb_enable_collect_execution_info=0;")
tk.MustExec("drop table if exists UK_GCOL_VIRTUAL_18588;")
tk.MustExec("CREATE TABLE `UK_GCOL_VIRTUAL_18588` (`COL1` bigint(20), UNIQUE KEY `UK_COL1` (`COL1`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
tk.MustExec("insert into UK_GCOL_VIRTUAL_18588 values('8502658334322817163');")
tk.MustExec(`prepare stmt from 'select col1 from UK_GCOL_VIRTUAL_18588 where col1 between ? and ? or col1 < ?';`)
tk.MustExec("set @a=5516958330762833919, @b=8551969118506051323, @c=2887622822023883594;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows("8502658334322817163"))

tkProcess := tk.Se.ShowProcess()
ps := []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res := tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 3)
c.Assert(res.Rows()[1][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexRangeScan.*")

tk.MustExec("set @a=-1696020282760139948, @b=-2619168038882941276, @c=-4004648990067362699;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 3)
c.Assert(res.Rows()[1][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexFullScan.*")

res = tk.MustQuery("explain format = 'brief' select col1 from UK_GCOL_VIRTUAL_18588 use index(UK_COL1) " +
"where col1 between -1696020282760139948 and -2619168038882941276 or col1 < -4004648990067362699;")
c.Assert(len(res.Rows()), Equals, 3)
c.Assert(res.Rows()[1][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexFullScan.*")
res = tk.MustQuery("explain format = 'brief' select col1 from UK_GCOL_VIRTUAL_18588 use index(UK_COL1) " +
"where col1 between 5516958330762833919 and 8551969118506051323 or col1 < 2887622822023883594;")
c.Assert(len(res.Rows()), Equals, 2)
c.Assert(res.Rows()[1][0], Matches, ".*IndexRangeScan.*")

tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE t (a int, b int, index idx(a, b));")
tk.MustExec("insert into t values(1, 0);")
tk.MustExec(`prepare stmt from 'select a from t where (a between ? and ? or a < ?) and b < 1;'`)
tk.MustExec("set @a=0, @b=2, @c=2;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows("1"))
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[2][3], Matches, ".*expression_index.*")
c.Assert(res.Rows()[2][4], Matches, ".*[1234,1234].*")
c.Assert(res.Rows()[1][0], Matches, ".*IndexReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1), or(and(ge(test.t.a, 0), le(test.t.a, 2)), lt(test.t.a, 2))")
c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*")

tk.MustExec("set @a=2, @b=1, @c=1;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*IndexReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1), or(and(ge(test.t.a, 2), le(test.t.a, 1)), lt(test.t.a, 1))")
c.Assert(res.Rows()[3][0], Matches, ".*IndexFullScan.*")

res = tk.MustQuery("explain format = 'brief' select a from t use index(idx) " +
"where (a between 0 and 2 or a < 2) and b < 1;")
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*IndexReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1)")
c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*")
res = tk.MustQuery("explain format = 'brief' select a from t use index(idx) " +
"where (a between 2 and 1 or a < 1) and b < 1;")
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*IndexReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1)")
c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*")

// test for indexLookUp
tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE t (a int, b int, index idx(a));")
tk.MustExec("insert into t values(1, 0);")
tk.MustExec(`prepare stmt from 'select a from t where (a between ? and ? or a < ?) and b < 1;'`)
tk.MustExec("set @a=0, @b=2, @c=2;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows("1"))
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 6)
c.Assert(res.Rows()[1][0], Matches, ".*IndexLookUp.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*")

tk.MustExec("set @a=2, @b=1, @c=1;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 6)
c.Assert(res.Rows()[1][0], Matches, ".*IndexLookUp.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[3][0], Matches, ".*IndexFullScan.*")

res = tk.MustQuery("explain format = 'brief' select a from t use index(idx) " +
"where (a between 0 and 2 or a < 2) and b < 1;")
c.Assert(len(res.Rows()), Equals, 5)
c.Assert(res.Rows()[1][0], Matches, ".*IndexLookUp.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexRangeScan.*")
res = tk.MustQuery("explain format = 'brief' select a from t use index(idx) " +
"where (a between 2 and 1 or a < 1) and b < 1;")
c.Assert(len(res.Rows()), Equals, 5)
c.Assert(res.Rows()[1][0], Matches, ".*IndexLookUp.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexRangeScan.*")

// test for tableReader
tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE t (a int PRIMARY KEY CLUSTERED, b int);")
tk.MustExec("insert into t values(1, 0);")
tk.MustExec(`prepare stmt from 'select a from t where (a between ? and ? or a < ?) and b < 1;'`)
tk.MustExec("set @a=0, @b=2, @c=2;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows("1"))
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*TableReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1), or(and(ge(test.t.a, 0), le(test.t.a, 2)), lt(test.t.a, 2))")
c.Assert(res.Rows()[3][0], Matches, ".*TableRangeScan.*")

tk.MustExec("set @a=2, @b=1, @c=1;")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*TableReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1), or(and(ge(test.t.a, 2), le(test.t.a, 1)), lt(test.t.a, 1))")
c.Assert(res.Rows()[3][0], Matches, ".*TableRangeScan.*")

res = tk.MustQuery("explain format = 'brief' select a from t " +
"where (a between 0 and 2 or a < 2) and b < 1;")
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*TableReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1)")
c.Assert(res.Rows()[3][0], Matches, ".*TableRangeScan.*")
res = tk.MustQuery("explain format = 'brief' select a from t " +
"where (a between 2 and 1 or a < 1) and b < 1;")
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[1][0], Matches, ".*TableReader.*")
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][4], Equals, "lt(test.t.b, 1)")
c.Assert(res.Rows()[3][0], Matches, ".*TableRangeScan.*")

tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE t (a int primary key, b int, c int, d int);")
tk.MustExec(`prepare stmt from 'select * from t where ((a > ? and a < 5 and b > 2) or (a > ? and a < 10 and c > 3)) and d = 5;';`)
tk.MustExec("set @a=1, @b=8;")
tk.MustQuery("execute stmt using @a,@b;").Check(testkit.Rows())
tkProcess = tk.Se.ShowProcess()
ps = []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
c.Assert(len(res.Rows()), Equals, 3)
c.Assert(res.Rows()[0][0], Matches, ".*TableReader.*")
c.Assert(res.Rows()[1][0], Matches, ".*Selection.*")
// The duplicate expressions can not be eliminated because the conditions are not the same.
// So this may be a bad case in some situations.
c.Assert(res.Rows()[1][4], Equals, "eq(test.t.d, 5), or(and(gt(test.t.a, 1), and(lt(test.t.a, 5), gt(test.t.b, 2))), and(gt(test.t.a, 8), and(lt(test.t.a, 10), gt(test.t.c, 3)))), or(and(gt(test.t.a, 1), lt(test.t.a, 5)), and(gt(test.t.a, 8), lt(test.t.a, 10)))")
c.Assert(res.Rows()[2][0], Matches, ".*TableRangeScan.*")
}
11 changes: 7 additions & 4 deletions executor/prepared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,15 +613,17 @@ func (s *testSerialSuite) TestIssue28064(c *C) {
"`d` decimal(10,0) DEFAULT NULL," +
"KEY `iabc` (`a`,`b`,`c`));")
tk.MustExec("set @a='123', @b='234', @c='345';")
tk.MustExec("set @@tidb_enable_collect_execution_info=0;")
tk.MustExec("prepare stmt1 from 'select * from t28064 use index (iabc) where a = ? and b = ? and c = ?';")

tk.MustExec("execute stmt1 using @a, @b, @c;")
tkProcess := tk.Se.ShowProcess()
ps := []*util.ProcessInfo{tkProcess}
tk.Se.SetSessionManager(&mockSessionManager1{PS: ps})
rows := tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID))
rows.Check(testkit.Rows("IndexLookUp_7 0.00 root ",
"├─IndexRangeScan_5(Build) 0.00 cop[tikv] table:t28064, index:iabc(a, b, c) range:[123 234 345,123 234 345], keep order:false, stats:pseudo",
rows.Check(testkit.Rows("IndexLookUp_8 0.00 root ",
"├─Selection_7(Build) 0.00 cop[tikv] eq(test.t28064.a, 123), eq(test.t28064.b, 234), eq(test.t28064.c, 345)",
"│ └─IndexRangeScan_5 0.00 cop[tikv] table:t28064, index:iabc(a, b, c) range:[123 234 345,123 234 345], keep order:false, stats:pseudo",
"└─TableRowIDScan_6(Probe) 0.00 cop[tikv] table:t28064 keep order:false, stats:pseudo"))

tk.MustExec("execute stmt1 using @a, @b, @c;")
Expand All @@ -630,7 +632,8 @@ func (s *testSerialSuite) TestIssue28064(c *C) {

tk.MustExec("execute stmt1 using @a, @b, @c;")
rows = tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID))
rows.Check(testkit.Rows("IndexLookUp_7 0.00 root ",
"├─IndexRangeScan_5(Build) 0.00 cop[tikv] table:t28064, index:iabc(a, b, c) range:[123 234 345,123 234 345], keep order:false, stats:pseudo",
rows.Check(testkit.Rows("IndexLookUp_8 0.00 root ",
"├─Selection_7(Build) 0.00 cop[tikv] eq(test.t28064.a, 123), eq(test.t28064.b, 234), eq(test.t28064.c, 345)",
"│ └─IndexRangeScan_5 0.00 cop[tikv] table:t28064, index:iabc(a, b, c) range:[123 234 345,123 234 345], keep order:false, stats:pseudo",
"└─TableRowIDScan_6(Probe) 0.00 cop[tikv] table:t28064 keep order:false, stats:pseudo"))
}
23 changes: 13 additions & 10 deletions executor/testdata/prepare_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@
],
"Plan": [
"Projection_4 10.00 root test.t1.a",
"└─IndexReader_6 10.00 root index:IndexRangeScan_5",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[3,3], keep order:false, stats:pseudo"
"└─IndexReader_7 0.00 root index:Selection_6",
" └─Selection_6 0.00 cop[tikv] eq(test.t1.b, 3)",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[3,3], keep order:false, stats:pseudo"
],
"LastPlanUseCache": "0",
"Result": [
Expand All @@ -101,8 +102,9 @@
],
"Plan": [
"Projection_4 10.00 root test.t1.a",
"└─IndexReader_6 10.00 root index:IndexRangeScan_5",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[2,2], keep order:false, stats:pseudo"
"└─IndexReader_7 0.00 root index:Selection_6",
" └─Selection_6 0.00 cop[tikv] eq(test.t1.b, 2)",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[2,2], keep order:false, stats:pseudo"
],
"LastPlanUseCache": "1",
"Result": [
Expand All @@ -119,8 +121,9 @@
],
"Plan": [
"Projection_4 10.00 root test.t1.a",
"└─IndexReader_6 10.00 root index:IndexRangeScan_5",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[-200,-200], keep order:false, stats:pseudo"
"└─IndexReader_7 0.00 root index:Selection_6",
" └─Selection_6 0.00 cop[tikv] eq(test.t1.b, -200)",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[-200,-200], keep order:false, stats:pseudo"
],
"LastPlanUseCache": "1",
"Result": null
Expand Down Expand Up @@ -158,11 +161,11 @@
"Plan": [
"HashJoin_38 6387.21 root inner join, equal:[eq(test.t1.b, test.t2.b) eq(test.t1.a, test.t2.a)]",
"├─IndexLookUp_63(Build) 99.80 root ",
"│ ├─Selection_62(Build) 99.80 cop[tikv] not(isnull(test.t2.b))",
"│ ├─Selection_62(Build) 99.80 cop[tikv] eq(test.t2.b, 1), not(isnull(test.t2.a)), not(isnull(test.t2.b))",
"│ │ └─IndexRangeScan_60 99.90 cop[tikv] table:t2, index:b(b, a) range:[1 -inf,1 +inf], keep order:false, stats:pseudo",
"│ └─TableRowIDScan_61(Probe) 99.80 cop[tikv] table:t2 keep order:false, stats:pseudo",
"└─IndexLookUp_56(Probe) 99.80 root ",
" ├─Selection_55(Build) 99.80 cop[tikv] not(isnull(test.t1.b))",
" ├─Selection_55(Build) 99.80 cop[tikv] eq(test.t1.b, 1), not(isnull(test.t1.a)), not(isnull(test.t1.b))",
" │ └─IndexRangeScan_53 99.90 cop[tikv] table:t1, index:b(b, a) range:[1 -inf,1 +inf], keep order:false, stats:pseudo",
" └─TableRowIDScan_54(Probe) 99.80 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
Expand All @@ -180,11 +183,11 @@
"Plan": [
"HashJoin_38 6387.21 root inner join, equal:[eq(test.t1.b, test.t2.b) eq(test.t1.a, test.t2.a)]",
"├─IndexLookUp_63(Build) 99.80 root ",
"│ ├─Selection_62(Build) 99.80 cop[tikv] not(isnull(test.t2.b))",
"│ ├─Selection_62(Build) 99.80 cop[tikv] eq(test.t2.b, 2), not(isnull(test.t2.a)), not(isnull(test.t2.b))",
"│ │ └─IndexRangeScan_60 99.90 cop[tikv] table:t2, index:b(b, a) range:[2 -inf,2 +inf], keep order:false, stats:pseudo",
"│ └─TableRowIDScan_61(Probe) 99.80 cop[tikv] table:t2 keep order:false, stats:pseudo",
"└─IndexLookUp_56(Probe) 99.80 root ",
" ├─Selection_55(Build) 99.80 cop[tikv] not(isnull(test.t1.b))",
" ├─Selection_55(Build) 99.80 cop[tikv] eq(test.t1.b, 2), not(isnull(test.t1.a)), not(isnull(test.t1.b))",
" │ └─IndexRangeScan_53 99.90 cop[tikv] table:t1, index:b(b, a) range:[2 -inf,2 +inf], keep order:false, stats:pseudo",
" └─TableRowIDScan_54(Probe) 99.80 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
Expand Down
Loading

0 comments on commit 091ae3b

Please sign in to comment.