Skip to content

Commit

Permalink
planner: rebuild range when the range is empty (#30003) (#30146)
Browse files Browse the repository at this point in the history
close #29993
  • Loading branch information
ti-srebot committed Feb 23, 2022
1 parent 5d6aa4e commit efa86e2
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 5 deletions.
2 changes: 1 addition & 1 deletion executor/prepared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ func (s *testPrepareSuite) TestPlanCacheOperators(c *C) {
}},
{"select a from t where a>? and a<?", []ExecCase{
{[]string{"5", "1"}, false},
{[]string{"1", "4"}, true},
{[]string{"1", "4"}, false},
{[]string{"3", "9"}, true},
}},
{"drop table t", nil},
Expand Down
12 changes: 12 additions & 0 deletions planner/core/common_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,9 @@ func (e *Execute) rebuildRange(p Plan) error {
if err != nil {
return err
}
if len(ranges.Ranges) == 0 || len(ranges.AccessConds) != len(x.AccessConditions) {
return errors.New("failed to rebuild range: the length of the range has changed")
}
for i := range x.IndexValues {
x.IndexValues[i] = ranges.Ranges[0].LowVal[i]
}
Expand All @@ -630,6 +633,9 @@ func (e *Execute) rebuildRange(p Plan) error {
if err != nil {
return err
}
if len(ranges) == 0 {
return errors.New("failed to rebuild range: the length of the range has changed")
}
x.Handle = kv.IntHandle(ranges[0].LowVal[0].GetInt64())
}
}
Expand Down Expand Up @@ -663,6 +669,9 @@ func (e *Execute) rebuildRange(p Plan) error {
if err != nil {
return err
}
if len(ranges.Ranges) != len(x.IndexValues) || len(ranges.AccessConds) != len(x.AccessConditions) {
return errors.New("failed to rebuild range: the length of the range has changed")
}
for i := range x.IndexValues {
for j := range ranges.Ranges[i].LowVal {
x.IndexValues[i][j] = ranges.Ranges[i].LowVal[j]
Expand All @@ -680,6 +689,9 @@ func (e *Execute) rebuildRange(p Plan) error {
if err != nil {
return err
}
if len(ranges) != len(x.Handles) {
return errors.New("failed to rebuild range: the length of the range has changed")
}
for i := range ranges {
x.Handles[i] = kv.IntHandle(ranges[i].LowVal[0].GetInt64())
}
Expand Down
6 changes: 5 additions & 1 deletion planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,11 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
continue
}
// if we already know the range of the scan is empty, just return a TableDual
if len(path.Ranges) == 0 && !ds.ctx.GetSessionVars().StmtCtx.UseCache {
if len(path.Ranges) == 0 {
// We should uncache the tableDual plan.
if expression.MaybeOverOptimized4PlanCache(ds.ctx, path.AccessConds) {
ds.ctx.GetSessionVars().StmtCtx.MaybeOverOptimized4PlanCache = true
}
dual := PhysicalTableDual{}.Init(ds.ctx, ds.stats, ds.blockOffset)
dual.SetSchema(ds.schema)
cntPlan += 1
Expand Down
121 changes: 118 additions & 3 deletions planner/core/prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,13 +621,14 @@ func (s *testPrepareSerialSuite) TestIssue31280(c *C) {
tk.MustExec(`prepare stmt from 'select * from UK_MU15569 where col2 >= ? and col1 is not null and col3 = ?;';`)

tk.MustExec("set @a=-32373, @b='545:50:46.85487';")
// The tableDual plan can not be cached.
res := tk.MustQuery("execute stmt using @a,@b;")
c.Assert(len(res.Rows()), Equals, 0)

tk.MustExec("set @a=-27225, @b='-836:46:08';")
res = tk.MustQuery("execute stmt using @a,@b;")
c.Assert(len(res.Rows()), Equals, 1)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @a,@b;")
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))

Expand Down Expand Up @@ -667,11 +668,12 @@ func (s *testPrepareSerialSuite) TestIssue31375(c *C) {
tk.MustExec(`prepare stmt from 'SELECT/*+ HASH_JOIN(t1, t2) */ t2.* FROM IDT_MULTI15844STROBJSTROBJ t1 LEFT JOIN IDT_MULTI15844STROBJSTROBJ t2 ON t1.col1 = t2.col1 WHERE t1.col2 BETWEEN ? AND ? AND t1.col1 >= ?;';`)

tk.MustExec("set @a=752400293960, @b=258241896853, @c='none';")
// The tableDual plan can not be cached.
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows())

tk.MustExec("set @a=-170756280585, @b=3756, @c='aa';")
tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows("bb -16994 1987"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @a,@b,@c;")
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
}
Expand Down Expand Up @@ -1938,14 +1940,127 @@ func (s *testPrepareSerialSuite) TestIssue28246(c *C) {
tk.MustExec("set @a=9223372036854775807, @b=1")
tk.MustExec(`prepare stmt from 'select min(col1) from PK_AUTO_RANDOM9111 where col1 > ?;';`)
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("<nil>"))
// The plan contains the tableDual, so it will not be cached.
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("<nil>"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @b").Check(testkit.Rows("9223372036854775807"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("<nil>"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("<nil>"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
}

func (s *testPrepareSerialSuite) TestIssue29993(c *C) {
defer testleak.AfterTest(c)()
store, dom, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
tk := testkit.NewTestKit(c, store)
orgEnable := core.PreparedPlanCacheEnabled()
defer func() {
dom.Close()
err = store.Close()
c.Assert(err, IsNil)
core.SetPreparedPlanCache(orgEnable)
}()
core.SetPreparedPlanCache(true)
tk.Se, err = session.CreateSession4TestWithOpt(store, &session.Opt{
PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64),
})
c.Assert(err, IsNil)

tk.MustExec("use test")

// test PointGet + cluster index
tk.MustExec("set tidb_enable_clustered_index=on;")
tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL PRIMARY KEY, col2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
tk.MustExec("insert into t values('a', 1), ('b', 2);")
tk.MustExec("set @a='a', @b='b', @z='z';")
tk.MustExec(`prepare stmt from 'select col1 from t where col1 = ? and col2 in (1, 2);';`)
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a"))
tk.MustQuery("execute stmt using @b").Check(testkit.Rows("b"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())
// The length of range have been changed, so the plan can not be cached.
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())

// test batchPointGet + cluster index
tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL, col2 int, PRIMARY KEY(col1, col2)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
tk.MustExec("insert into t values('a', 1), ('b', 2);")
tk.MustExec("set @a='a', @b='b', @z='z';")
tk.MustExec(`prepare stmt from 'select col1 from t where (col1, col2) in ((?, 1));';`)
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a"))
tk.MustQuery("execute stmt using @b").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())

// test PointGet + non cluster index
tk.MustExec("set tidb_enable_clustered_index=off;")
tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL PRIMARY KEY, col2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
tk.MustExec("insert into t values('a', 1), ('b', 2);")
tk.MustExec("set @a='a', @b='b', @z='z';")
tk.MustExec(`prepare stmt from 'select col1 from t where col1 = ? and col2 in (1, 2);';`)
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a"))
tk.MustQuery("execute stmt using @b").Check(testkit.Rows("b"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())
// The length of range have been changed, so the plan can not be cached.
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())

// test batchPointGet + non cluster index
tk.MustExec("drop table if exists t;")
tk.MustExec("CREATE TABLE `t` (`COL1` enum('a', 'b') NOT NULL, col2 int, PRIMARY KEY(col1, col2)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
tk.MustExec("insert into t values('a', 1), ('b', 2);")
tk.MustExec("set @a='a', @b='b', @z='z';")
tk.MustExec(`prepare stmt from 'select col1 from t where (col1, col2) in ((?, 1));';`)
tk.MustQuery("execute stmt using @a").Check(testkit.Rows("a"))
tk.MustQuery("execute stmt using @b").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt using @z").Check(testkit.Rows())
}

func (s *testPrepareSerialSuite) TestIssue30100(c *C) {
defer testleak.AfterTest(c)()
store, dom, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
tk := testkit.NewTestKit(c, store)
orgEnable := core.PreparedPlanCacheEnabled()
defer func() {
dom.Close()
err = store.Close()
c.Assert(err, IsNil)
core.SetPreparedPlanCache(orgEnable)
}()
core.SetPreparedPlanCache(true)
tk.Se, err = session.CreateSession4TestWithOpt(store, &session.Opt{
PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64),
})
c.Assert(err, IsNil)

tk.MustExec("use test")
tk.MustExec("drop table if exists t;")
tk.MustExec("create table t(col1 enum('aa', 'bb'), col2 int, index(col1, col2));")
tk.MustExec("insert into t values('aa', 333);")
tk.MustExec(`prepare stmt from 'SELECT * FROM t t1 JOIN t t2 ON t1.col1 = t2.col1 WHERE t1.col1 <=> NULL';`)
tk.MustQuery("execute stmt").Check(testkit.Rows())
tk.MustQuery("execute stmt").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))

tk.MustExec(`prepare stmt from 'SELECT * FROM t t1 JOIN t t2 ON t1.col1 = t2.col1 WHERE t1.col1 <=> NULL and t2.col2 > ?';`)
tk.MustExec("set @a=0;")
tk.MustQuery("execute stmt using @a").Check(testkit.Rows())
tk.MustQuery("execute stmt using @a").Check(testkit.Rows())
}

func (s *testPlanSerialSuite) TestPartitionTable(c *C) {
if israce.RaceEnabled {
c.Skip("exhaustive types test, skip race test")
Expand Down

0 comments on commit efa86e2

Please sign in to comment.