Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: generate addition selection when plan cache enable #28457

Merged
merged 17 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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