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: non-prep plan cache supports regular builtin-functions #42554

Merged
merged 1 commit into from
Mar 25, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 0 additions & 12 deletions expression/function_traits.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,6 @@ import (
"github.com/pingcap/tidb/parser/opcode"
)

// NonPreparedPlanCacheableOp stores function which can be cached to non-prepared plan cache.
var NonPreparedPlanCacheableOp = map[string]struct{}{
ast.LogicAnd: {},
ast.LogicOr: {},
ast.GE: {},
ast.LE: {},
ast.EQ: {},
ast.LT: {},
ast.GT: {},
ast.In: {},
}

// UnCacheableFunctions stores functions which can not be cached to plan cache.
var UnCacheableFunctions = map[string]struct{}{
ast.Database: {},
Expand Down
47 changes: 38 additions & 9 deletions planner/core/plan_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,6 @@ func TestNonPreparedPlanCacheReason(t *testing.T) {
tk.MustExec(`explain format = 'plan_cache' select * from t where a=1`)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))

tk.MustExec(`explain format = 'plan_cache' select * from t where a+1=1`)
tk.MustQuery(`show warnings`).Check(testkit.Rows(`Warning 1105 skip non-prepared plan-cache: query has some unsupported binary operation`))

tk.MustExec(`explain format = 'plan_cache' select * from t t1, t t2`)
tk.MustQuery(`show warnings`).Check(testkit.Rows(`Warning 1105 skip non-prepared plan-cache: queries that access multiple tables are not supported`))

Expand Down Expand Up @@ -1492,6 +1489,9 @@ func TestNonPreparedPlanExplainWarning(t *testing.T) {
"select * from t where a in (1, 2) and b < 15",
"select * from t where a between 1 and 10",
"select * from t where a between 1 and 10 and b < 15",
"select * from t where a+b=13",
"select * from t where mod(a, 3)=1",
"select * from t where d>now()",
}

unsupported := []string{
Expand All @@ -1510,9 +1510,6 @@ func TestNonPreparedPlanExplainWarning(t *testing.T) {
"select * from t1 for update", // lock
"select * from t1 where a in (select a from t)", // uncorrelated sub-query
"select * from t1 where a in (select a from t where a > t1.a)", // correlated sub-query
"select * from t where a+b=13", // '+'
"select * from t where mod(a, 3)=1", // mod
"select * from t where d>now()", // now
"select * from t where j < 1", // json
"select * from t where a > 1 and j < 1",
"select * from t where e < '1'", // enum
Expand Down Expand Up @@ -1550,9 +1547,6 @@ func TestNonPreparedPlanExplainWarning(t *testing.T) {
"skip non-prepared plan-cache: queries that have hints, aggregation, window-function, order-by, limit and lock are not supported",
"skip non-prepared plan-cache: queries that access partitioning table are not supported",
"skip non-prepared plan-cache: queries that access partitioning table are not supported",
"skip non-prepared plan-cache: query has some unsupported binary operation",
"skip non-prepared plan-cache: query has some unsupported binary operation",
"skip non-prepared plan-cache: query has some unsupported Node",
"skip non-prepared plan-cache: query has some filters with JSON, Enum, Set or Bit columns",
"skip non-prepared plan-cache: query has some filters with JSON, Enum, Set or Bit columns",
"skip non-prepared plan-cache: query has some filters with JSON, Enum, Set or Bit columns",
Expand Down Expand Up @@ -1659,6 +1653,41 @@ func TestNonPreparedPlanCachePanic(t *testing.T) {
}
}

func TestNonPreparedPlanCacheBuiltinFuncs(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`set tidb_enable_non_prepared_plan_cache=1`)
tk.MustExec(`create table t (a int, b varchar(32), c datetime, key(a))`)

// normal builtin functions can be supported
supportedCases := []string{
`select * from t where mod(a, 5) < 2`,
`select * from t where c < now()`,
`select date_format(c, '%Y-%m-%d') from t where a < 10`,
`select str_to_date(b, '%Y-%m-%d') from t where a < 10`,
`select * from t where a-2 < 20`,
`select * from t where a+b > 100`,
}
for _, sql := range supportedCases {
tk.MustExec(sql)
tk.MustExec(sql)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
}

// unsupported cases
unsupportedCases := []string{
`select * from t where -a > 10`, // '-' cannot support
`select * from t where a < 1 and b like '%abc%'`, // LIKE
`select database() from t`,
}
for _, sql := range unsupportedCases {
tk.MustExec(sql)
tk.MustExec(sql)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
}
}

func BenchmarkPlanCacheInsert(b *testing.B) {
store := testkit.CreateMockStore(b)
tk := testkit.NewTestKit(b, store)
Expand Down
8 changes: 4 additions & 4 deletions planner/core/plan_cacheable_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func (checker *nonPreparedPlanCacheableChecker) Enter(in ast.Node) (out ast.Node

switch node := in.(type) {
case *ast.SelectStmt, *ast.FieldList, *ast.SelectField, *ast.TableRefsClause, *ast.Join, *ast.BetweenExpr,
*ast.TableSource, *ast.ColumnNameExpr, *ast.PatternInExpr:
*ast.TableSource, *ast.ColumnNameExpr, *ast.PatternInExpr, *ast.BinaryOperationExpr:
return in, !checker.cacheable // skip child if un-cacheable
case *ast.ColumnName:
if checker.filterCnt > 0 {
Expand All @@ -306,10 +306,10 @@ func (checker *nonPreparedPlanCacheableChecker) Enter(in ast.Node) (out ast.Node
}
}
return in, !checker.cacheable
case *ast.BinaryOperationExpr:
if _, found := expression.NonPreparedPlanCacheableOp[node.Op.String()]; !found {
case *ast.FuncCallExpr:
if _, found := expression.UnCacheableFunctions[node.FnName.L]; found {
checker.cacheable = false
checker.reason = "query has some unsupported binary operation"
checker.reason = "query has un-cacheable functions"
}
return in, !checker.cacheable
case *driver.ValueExpr:
Expand Down
7 changes: 3 additions & 4 deletions planner/core/plan_cacheable_checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ func TestNonPreparedPlanCacheable(t *testing.T) {
"select * from test.t where a in (1, 2) and b < 15",
"select * from test.t where a between 1 and 10",
"select * from test.t where a between 1 and 10 and b < 15",
"select * from test.t where a+b=13", // '+'
"select * from test.t where mod(a, 3)=1", // mod
"select * from test.t where d>now()", // now
}

unsupported := []string{
Expand All @@ -316,10 +319,6 @@ func TestNonPreparedPlanCacheable(t *testing.T) {
"select * from test.t1 for update", // lock
"select * from test.t1 where a in (select a from t)", // uncorrelated sub-query
"select * from test.t1 where a in (select a from test.t where a > t1.a)", // correlated sub-query

"select * from test.t where a+b=13", // '+'
"select * from test.t where mod(a, 3)=1", // mod
"select * from test.t where d>now()", // now
}

for _, q := range unsupported {
Expand Down