Skip to content

Commit

Permalink
planner: rebuild range when the range is empty (#30003)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reminiscent authored Nov 25, 2021
1 parent 7f93b09 commit 78c653e
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 7 deletions.
5 changes: 0 additions & 5 deletions executor/prepared_serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,11 +706,6 @@ func TestPlanCacheOperators(t *testing.T) {

// execute this statement and check whether it uses a cached plan
results := tk.MustQuery("execute stmt " + usingStmt).Sort().Rows()
useCache := "0"
if execCase.UseCache {
useCache = "1"
}
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows(useCache))

// check whether the result is correct
tmp := strings.Split(prepCase.PrepStmt, "?")
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 @@ -610,6 +610,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 @@ -625,6 +628,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 @@ -658,6 +664,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 @@ -675,6 +684,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
116 changes: 115 additions & 1 deletion planner/core/prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1850,8 +1850,11 @@ 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"))
}
Expand Down Expand Up @@ -1891,6 +1894,117 @@ func (s *testPrepareSerialSuite) TestIssue29805(c *C) {
tk.MustQuery("select/*+ hash_agg() */ count(distinct col1) from PK_TCOLLATION10197 where col1 > '龺';").Check(testkit.Rows("0"))
}

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())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
}

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

0 comments on commit 78c653e

Please sign in to comment.