From bc52ce07398ba5698be41fd68f34cdb59a059ff6 Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Mon, 20 Feb 2023 22:09:13 +0800 Subject: [PATCH] planner: add more test cases for non-prep plan cache (#41608) ref pingcap/tidb#36598 --- planner/core/plan_cache_test.go | 65 ++++++++++++++++++++++++++ planner/core/plan_cacheable_checker.go | 7 +++ 2 files changed, 72 insertions(+) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index 640bb2ee3b..261f2a099e 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -290,6 +290,71 @@ func TestNonPreparedPlanCacheFallback(t *testing.T) { require.NotNil(t, err) } +func TestNonPreparedPlanCacheFastPointGet(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec(`use test`) + tk.MustExec(`create table t (a int primary key, b int, unique key(b))`) + tk.MustExec(`set tidb_enable_non_prepared_plan_cache=1`) + + // fast plans have a higher priority than non-prep cache plan + tk.MustQuery(`explain format='brief' select a from t where a in (1, 2)`).Check(testkit.Rows( + `Batch_Point_Get 2.00 root table:t handle:[1 2], keep order:false, desc:false`)) + tk.MustQuery(`select a from t where a in (1, 2)`).Check(testkit.Rows()) + tk.MustQuery(`select a from t where a in (1, 2)`).Check(testkit.Rows()) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + + tk.MustQuery(`explain format='brief' select b from t where b = 1`).Check(testkit.Rows( + `Point_Get 1.00 root table:t, index:b(b) `)) + tk.MustQuery(`select b from t where b = 1`).Check(testkit.Rows()) + tk.MustQuery(`select b from t where b = 1`).Check(testkit.Rows()) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) +} + +func TestNonPreparedPlanCacheSetOperations(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec(`use test`) + tk.MustExec(`create table t (a int)`) + tk.MustExec(`set tidb_enable_non_prepared_plan_cache=1`) + + // queries with set operations cannot hit the cache + for _, q := range []string{ + `select * from t union select * from t`, + `select * from t union distinct select * from t`, + `select * from t union all select * from t`, + `select * from t except select * from t`, + `select * from t intersect select * from t`, + } { + tk.MustQuery(q).Check(testkit.Rows()) + tk.MustQuery(q).Check(testkit.Rows()) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + } +} + +func TestNonPreparedPlanCacheSpecialTables(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec(`use test`) + tk.MustExec(`create table t (a int)`) + tk.MustExec(`create definer='root'@'localhost' view t_v as select * from t`) + tk.MustExec(`create table t_p (a int) partition by hash(a) partitions 4`) + tk.MustExec(`create temporary table t_t (a int)`) + tk.MustExec(`set tidb_enable_non_prepared_plan_cache=1`) + + // queries that access partitioning tables, view, temporary tables or contain CTE cannot hit the cache. + for _, q := range []string{ + `select * from t_v`, + `select * from t_p`, + `select * from t_t`, + `with t_cte as (select * from t) select * from t_cte`, + } { + tk.MustQuery(q).Check(testkit.Rows()) + tk.MustQuery(q).Check(testkit.Rows()) + tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0")) + } +} + func TestNonPreparedPlanCacheBasically(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) diff --git a/planner/core/plan_cacheable_checker.go b/planner/core/plan_cacheable_checker.go index aee19c96a9..cfb38c2882 100644 --- a/planner/core/plan_cacheable_checker.go +++ b/planner/core/plan_cacheable_checker.go @@ -275,6 +275,9 @@ func (checker *nonPreparedPlanCacheableChecker) Enter(in ast.Node) (out ast.Node if isTempTable(checker.schema, node) { checker.cacheable = false } + if isView(checker.schema, node) { + checker.cacheable = false + } } return in, !checker.cacheable } @@ -301,6 +304,10 @@ func hasGeneratedCol(schema infoschema.InfoSchema, tn *ast.TableName) bool { return false } +func isView(schema infoschema.InfoSchema, tn *ast.TableName) bool { + return schema.TableIsView(tn.Schema, tn.Name) +} + func isTempTable(schema infoschema.InfoSchema, tn *ast.TableName) bool { tb, err := schema.TableByName(tn.Schema, tn.Name) if err != nil {