Skip to content

Commit

Permalink
planner: update the plan cache strategy when expressions with paramet…
Browse files Browse the repository at this point in the history
…ers affect null-check (#40218) (#42637)

close #38205
  • Loading branch information
qw4990 committed Mar 28, 2023
1 parent 89c0b5a commit c585770
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 28 deletions.
29 changes: 13 additions & 16 deletions executor/explainfor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,9 @@ func (s *testPrepareSerialSuite) TestIssue28259(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()[0][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[3][0], Matches, ".*IndexFullScan.*")
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;")
Expand Down Expand Up @@ -661,11 +661,9 @@ func (s *testPrepareSerialSuite) TestIssue28259(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, 5)
c.Assert(res.Rows()[1][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[1][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()[2][0], Matches, ".*IndexReader.*")
c.Assert(res.Rows()[4][0], Matches, ".*IndexRangeScan.*")
c.Assert(len(res.Rows()), Equals, 4)
c.Assert(res.Rows()[2][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*")

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;")
Expand Down Expand Up @@ -708,12 +706,11 @@ func (s *testPrepareSerialSuite) TestIssue28259(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, 6)
c.Assert(res.Rows()[1][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexLookUp.*")
c.Assert(res.Rows()[3][0], Matches, ".*IndexRangeScan.*")
c.Assert(res.Rows()[4][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[5][0], Matches, ".*TableRowIDScan.*")
c.Assert(len(res.Rows()), Equals, 5)
c.Assert(res.Rows()[1][0], Matches, ".*IndexLookUp.*")
c.Assert(res.Rows()[2][0], Matches, ".*IndexRangeScan.*")
c.Assert(res.Rows()[3][0], Matches, ".*Selection.*")
c.Assert(res.Rows()[4][0], Matches, ".*TableRowIDScan.*")

res = tk.MustQuery("explain format = 'brief' select /*+ USE_INDEX(t, idx) */ a from t use index(idx) " +
"where (a between 0 and 2 or a < 2) and b < 1;")
Expand Down Expand Up @@ -952,7 +949,7 @@ func (s *testPrepareSerialSuite) TestIndexMerge4PlanCache(c *C) {
tk.MustExec("prepare stmt from 'select /*+ use_index_merge(t1) */ * from t1 where c=? or (b=? and (a >= ? and a <= ?));';")
tk.MustQuery("execute stmt using @a, @a, @b, @a").Check(testkit.Rows("10 10 10"))
tk.MustQuery("execute stmt using @b, @b, @b, @b").Check(testkit.Rows("11 11 11"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))

tk.MustExec("prepare stmt from 'select /*+ use_index_merge(t1) */ * from t1 where c=10 or (a >=? and a <= ?);';")
tk.MustExec("set @a=9, @b=10, @c=11;")
Expand All @@ -974,7 +971,7 @@ func (s *testPrepareSerialSuite) TestIndexMerge4PlanCache(c *C) {
tk.MustExec("set @a=9, @b=10, @c=11;")
tk.MustQuery("execute stmt using @c, @a;").Check(testkit.Rows("10 10 10"))
tk.MustQuery("execute stmt using @a, @c;").Check(testkit.Rows("10 10 10", "11 11 11"))
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, @a;").Check(testkit.Rows("10 10 10"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))

Expand Down
2 changes: 1 addition & 1 deletion expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ func SplitDNFItems(onExpr Expression) []Expression {
// If the Expression is a non-constant value, it means the result is unknown.
func EvaluateExprWithNull(ctx sessionctx.Context, schema *Schema, expr Expression) Expression {
if MaybeOverOptimized4PlanCache(ctx, []Expression{expr}) {
return expr
ctx.GetSessionVars().StmtCtx.SkipPlanCache = true
}
return evaluateExprWithNull(ctx, schema, expr)
}
Expand Down
5 changes: 3 additions & 2 deletions expression/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ func TestEvaluateExprWithNullAndParameters(t *testing.T) {
ltWithParam, err := newFunctionForTest(ctx, ast.LT, col0, param)
require.NoError(t, err)
res = EvaluateExprWithNull(ctx, schema, ltWithParam)
_, isScalarFunc := res.(*ScalarFunction)
require.True(t, isScalarFunc) // the expression with parameters is not evaluated
_, isConst := res.(*Constant)
require.True(t, isConst) // this expression is evaluated and skip-plan cache flag is set.
require.True(t, ctx.GetSessionVars().StmtCtx.SkipPlanCache)
}

func TestConstant(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions planner/core/prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2058,7 +2058,7 @@ func (s *testPlanSerialSuite) TestPlanCachePointGetAndTableDual(c *C) {
tk.MustQuery("execute s0 using @a0, @b0, @a0").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute s0 using @a0, @a0, @b0").Check(testkit.Rows("0000 7777 1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))

tk.MustExec("create table t1(c1 varchar(20), c2 varchar(20), c3 bigint(20), primary key(c1, c2))")
tk.MustExec("insert into t1 values('0000','7777',1)")
Expand Down Expand Up @@ -2096,7 +2096,7 @@ func (s *testPlanSerialSuite) TestPlanCachePointGetAndTableDual(c *C) {
tk.MustQuery("execute s3 using @b3,@a3").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute s3 using @a3,@b3").Check(testkit.Rows("2 1 1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))

tk.MustExec("create table t4(c1 int primary key, c2 int, c3 int, key(c2))")
tk.MustExec("insert into t4 values(2,1,1)")
Expand All @@ -2112,7 +2112,7 @@ func (s *testPlanSerialSuite) TestPlanCachePointGetAndTableDual(c *C) {
tk.MustQuery("execute s4 using @b4,@a4").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
tk.MustQuery("execute s4 using @a4,@b4").Check(testkit.Rows("2 1 1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
}

func (s *testPrepareSuite) TestIssue26873(c *C) {
Expand Down
10 changes: 4 additions & 6 deletions util/ranger/detacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,9 +537,8 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex
points[offset] = rb.intersection(points[offset], rb.build(cond, collator), collator)
if len(points[offset]) == 0 { // Early termination if false expression found
if expression.MaybeOverOptimized4PlanCache(sctx, conditions) {
// cannot return an empty-range for plan-cache since the range may become non-empty as parameters change
// for safety, return the whole conditions in this case
return nil, conditions, nil, nil, false
// `a>@x and a<@y` --> `invalid-range if @x>=@y`
sctx.GetSessionVars().StmtCtx.SkipPlanCache = true
}
return nil, nil, nil, nil, true
}
Expand All @@ -562,9 +561,8 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex
accesses[i] = nil
} else if len(points[i]) == 0 { // Early termination if false expression found
if expression.MaybeOverOptimized4PlanCache(sctx, conditions) {
// cannot return an empty-range for plan-cache since the range may become non-empty as parameters change
// for safety, return the whole conditions in this case
return nil, conditions, nil, nil, false
// `a>@x and a<@y` --> `invalid-range if @x>=@y`
sctx.GetSessionVars().StmtCtx.SkipPlanCache = true
}
return nil, nil, nil, nil, true
} else {
Expand Down

0 comments on commit c585770

Please sign in to comment.