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) (#40476)

close #38205, close #40093
  • Loading branch information
ti-chi-bot authored Jan 17, 2023
1 parent c8fc405 commit 4504bc3
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 25 deletions.
27 changes: 12 additions & 15 deletions executor/explainfor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,9 +613,9 @@ func TestIssue28259(t *testing.T) {
ps = []*util.ProcessInfo{tkProcess}
tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
require.Len(t, res.Rows(), 4)
require.Regexp(t, ".*Selection.*", res.Rows()[0][0])
require.Regexp(t, ".*IndexFullScan.*", res.Rows()[3][0])
require.Len(t, res.Rows(), 3)
require.Regexp(t, ".*Selection.*", res.Rows()[1][0])
require.Regexp(t, ".*IndexFullScan.*", res.Rows()[2][0])

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 @@ -651,11 +651,9 @@ func TestIssue28259(t *testing.T) {
ps = []*util.ProcessInfo{tkProcess}
tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
require.Len(t, res.Rows(), 5)
require.Regexp(t, ".*Selection.*", res.Rows()[1][0])
require.Equal(t, "lt(test.t.b, 1), or(and(ge(test.t.a, 2), le(test.t.a, 1)), lt(test.t.a, 1))", res.Rows()[1][4])
require.Regexp(t, ".*IndexReader.*", res.Rows()[2][0])
require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[4][0])
require.Len(t, res.Rows(), 4)
require.Regexp(t, ".*Selection.*", res.Rows()[2][0])
require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[3][0])

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 @@ -698,12 +696,11 @@ func TestIssue28259(t *testing.T) {
ps = []*util.ProcessInfo{tkProcess}
tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
res = tk.MustQuery("explain for connection " + strconv.FormatUint(tkProcess.ID, 10))
require.Len(t, res.Rows(), 6)
require.Regexp(t, ".*Selection.*", res.Rows()[1][0])
require.Regexp(t, ".*IndexLookUp.*", res.Rows()[2][0])
require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[3][0])
require.Regexp(t, ".*Selection.*", res.Rows()[4][0])
require.Regexp(t, ".*TableRowIDScan.*", res.Rows()[5][0])
require.Len(t, res.Rows(), 5)
require.Regexp(t, ".*IndexLookUp.*", res.Rows()[1][0])
require.Regexp(t, ".*IndexRangeScan.*", res.Rows()[2][0])
require.Regexp(t, ".*Selection.*", res.Rows()[3][0])
require.Regexp(t, ".*TableRowIDScan.*", res.Rows()[4][0])

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 @@ -946,7 +943,7 @@ func TestIndexMerge4PlanCache(t *testing.T) {
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 Down
4 changes: 4 additions & 0 deletions executor/stale_txn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,19 +533,23 @@ func TestStalenessTransactionSchemaVer(t *testing.T) {
tk.MustExec("alter table t add c int")

// confirm schema changed
time.Sleep(time.Millisecond * 20)
schemaVer2 := tk.Session().GetInfoSchema().SchemaMetaVersion()
require.Less(t, schemaVer1, schemaVer2)

// get the specific old schema
tk.MustExec(fmt.Sprintf(`START TRANSACTION READ ONLY AS OF TIMESTAMP '%s'`, time1.Format("2006-1-2 15:04:05.000")))
time.Sleep(time.Millisecond * 20)
require.Equal(t, schemaVer1, tk.Session().GetInfoSchema().SchemaMetaVersion())

// schema changed back to the newest
tk.MustExec("commit")
time.Sleep(time.Millisecond * 20)
require.Equal(t, schemaVer2, tk.Session().GetInfoSchema().SchemaMetaVersion())

// select does not affect the infoschema
tk.MustExec(fmt.Sprintf(`SELECT * from t AS OF TIMESTAMP '%s'`, time1.Format("2006-1-2 15:04:05.000")))
time.Sleep(time.Millisecond * 20)
require.Equal(t, schemaVer2, tk.Session().GetInfoSchema().SchemaMetaVersion())
}

Expand Down
2 changes: 1 addition & 1 deletion expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,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
2 changes: 1 addition & 1 deletion planner/core/prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2212,7 +2212,7 @@ func TestPlanCachePointGetAndTableDual(t *testing.T) {
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
10 changes: 4 additions & 6 deletions util/ranger/detacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,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 @@ -565,9 +564,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 4504bc3

Please sign in to comment.