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: allow refineArgs for plan cache in some situations #28944

Merged
merged 66 commits into from
Oct 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
45b208d
planner: allow refineArgs in plan cache in some situations
Reminiscent Oct 19, 2021
8f08d30
uncache the plan which can be optimized from refineArgs
Reminiscent Oct 20, 2021
41fb8aa
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 20, 2021
2579552
fix ut
Reminiscent Oct 20, 2021
9daea53
fix ut
Reminiscent Oct 20, 2021
176d97f
fix ut
Reminiscent Oct 20, 2021
9e32009
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 20, 2021
9233f5e
add more comments
Reminiscent Oct 20, 2021
b286def
fix ut
Reminiscent Oct 21, 2021
0359c5e
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 21, 2021
c6329e8
fix ut
Reminiscent Oct 21, 2021
89b373f
fix ut and add more comments
Reminiscent Oct 21, 2021
a0a8c09
fix typo
Reminiscent Oct 21, 2021
eda25e8
address comments
Reminiscent Oct 21, 2021
1ed192f
clean code
Reminiscent Oct 21, 2021
6f8102f
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 21, 2021
d2ea569
address comments
Reminiscent Oct 25, 2021
8621316
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 25, 2021
ea74ac8
remove useless lines
Reminiscent Oct 25, 2021
19930f4
address comments
Reminiscent Oct 25, 2021
dceab46
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 25, 2021
26a71d9
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
5f2316c
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
84a84f9
fix ut
Reminiscent Oct 25, 2021
d6da950
Merge remote-tracking branch 'origin/issue28858' into issue28858
Reminiscent Oct 25, 2021
65e6d89
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
dcdf30d
Merge branch 'master' into issue28858
qw4990 Oct 25, 2021
8b97255
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
020049b
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
b5cb626
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
5715f58
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
431b54a
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
1331474
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
019ebda
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
b796f76
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
8c6241c
Merge branch 'master' into issue28858
ti-chi-bot Oct 25, 2021
5e6473d
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 25, 2021
53a5c83
Merge remote-tracking branch 'origin/issue28858' into issue28858
Reminiscent Oct 25, 2021
9fedfc4
refine the code
Reminiscent Oct 26, 2021
21c21f1
Merge branch 'master' into issue28858
qw4990 Oct 26, 2021
070db48
Merge branch 'master' into issue28858
ti-chi-bot Oct 26, 2021
d96a1d0
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 26, 2021
bf982a1
Merge remote-tracking branch 'origin/issue28858' into issue28858
Reminiscent Oct 26, 2021
e3108c8
remove the test from executor package to planner package
Reminiscent Oct 26, 2021
d0b2442
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 26, 2021
43e78ba
Merge branch 'master' into issue28858
ti-chi-bot Oct 26, 2021
7e50e3a
Merge branch 'master' into issue28858
ti-chi-bot Oct 26, 2021
5b069b4
Merge branch 'master' into issue28858
ti-chi-bot Oct 26, 2021
7bdb557
Merge branch 'master' of github.com:pingcap/tidb into issue28858
Reminiscent Oct 26, 2021
1c3065f
Merge remote-tracking branch 'origin/issue28858' into issue28858
Reminiscent Oct 26, 2021
b21a736
Merge branch 'master' into issue28858
qw4990 Oct 27, 2021
010a0c8
Merge branch 'master' into issue28858
qw4990 Oct 29, 2021
5a0e17a
Merge branch 'master' into issue28858
ti-chi-bot Oct 29, 2021
831771a
Merge branch 'master' into issue28858
ti-chi-bot Oct 29, 2021
6e1a1c7
Merge branch 'master' into issue28858
ti-chi-bot Oct 29, 2021
07b3c84
Merge branch 'master' into issue28858
ti-chi-bot Oct 29, 2021
8cada8f
Merge branch 'master' into issue28858
ti-chi-bot Oct 29, 2021
e3f484c
skip unstable tests
Reminiscent Oct 29, 2021
00933ad
Merge branch 'issue28858' of github.com:Reminiscent/tidb into issue28858
Reminiscent Oct 29, 2021
8fe7f21
Merge branch 'master' into issue28858
Reminiscent Oct 29, 2021
2885631
fix ci
qw4990 Oct 29, 2021
6871a9e
fix ci
qw4990 Oct 29, 2021
dd1b4f7
Merge branch 'master' into issue28858
qw4990 Oct 29, 2021
2a18b6d
fix ci
qw4990 Oct 29, 2021
36c74af
Merge branch 'master' into issue28858
qw4990 Oct 29, 2021
272722c
Merge branch 'master' into issue28858
ti-chi-bot Oct 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions executor/explainfor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ type testPrepareSerialSuite struct {
}

func (s *testPrepareSerialSuite) TestExplainForConnPlanCache(c *C) {
c.Skip("unstable")
if israce.RaceEnabled {
c.Skip("skip race test")
}
Expand Down Expand Up @@ -287,10 +288,9 @@ func (s *testPrepareSerialSuite) TestExplainForConnPlanCache(c *C) {
explainQuery := "explain for connection " + strconv.FormatUint(tk1.Se.ShowProcess().ID, 10)

explainResult := testkit.Rows(
"Selection_8 8000.00 root eq(cast(test.t.a, double BINARY), 1)",
"└─TableReader_7 8000.00 root data:Selection_6",
" └─Selection_6 8000.00 cop[tikv] eq(cast(test.t.a, double BINARY), 1)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo",
"TableReader_7 10.00 root data:Selection_6",
"└─Selection_6 10.00 cop[tikv] eq(test.t.a, 1)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo",
)

// Now the ProcessInfo held by mockSessionManager1 will not be updated in real time.
Expand All @@ -303,6 +303,9 @@ func (s *testPrepareSerialSuite) TestExplainForConnPlanCache(c *C) {
PS: []*util.ProcessInfo{tk1.Se.ShowProcess()},
})
tk2.MustQuery(explainQuery).Check(explainResult)
tk1.MustExec(executeQuery)
// The plan can not be cached because the string type parameter will be convert to int type for calculation.
tk1.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))

// multiple test, '1000' is both effective and efficient.
repeats := 1000
Expand Down Expand Up @@ -904,7 +907,7 @@ func (s *testPrepareSerialSuite) TestIndexMerge4PlanCache(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(res.Rows()[1][0], Matches, ".*IndexMerge.*")
c.Assert(res.Rows()[0][0], Matches, ".*IndexMerge.*")

tk.MustQuery("execute stmt using @b;").Check(testkit.Rows("3 ddcdsaf 3"))
// TODO: should use plan cache here
Expand All @@ -914,7 +917,7 @@ func (s *testPrepareSerialSuite) TestIndexMerge4PlanCache(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(res.Rows()[1][0], Matches, ".*IndexMerge.*")
c.Assert(res.Rows()[0][0], Matches, ".*IndexMerge.*")

// rewrite the origin indexMerge test
tk.MustExec("drop table if exists t;")
Expand Down
2 changes: 1 addition & 1 deletion executor/prepared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ func (s *testSerialSuite) TestIssue28087And28162(c *C) {
tk.MustQuery(`execute stmt using @a,@b,@c`).Check(testkit.Rows("\x01"))
tk.MustExec(`set @a=0x00, @b=0x00, @c=0x01`)
tk.MustQuery(`execute stmt using @a,@b,@c`).Check(testkit.Rows("\x00", "\x01"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))

// issue 28162
tk.MustExec(`drop table if exists IDT_MC21780`)
Expand Down
24 changes: 10 additions & 14 deletions executor/testdata/prepare_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,9 @@
}
],
"Plan": [
"Projection_4 8000.00 root test.t1.a",
"└─Selection_12 8000.00 root eq(cast(test.t1.b, double BINARY), 0)",
" └─IndexReader_11 8000.00 root index:Selection_10",
" └─Selection_10 8000.00 cop[tikv] eq(cast(test.t1.b, double BINARY), 0)",
" └─IndexFullScan_9 10000.00 cop[tikv] table:t1, index:b(b, a) keep order:false, stats:pseudo"
"Projection_4 10.00 root test.t1.a",
"└─IndexReader_6 10.00 root index:IndexRangeScan_5",
" └─IndexRangeScan_5 10.00 cop[tikv] table:t1, index:b(b, a) range:[0,0], keep order:false, stats:pseudo"
],
"LastPlanUseCache": "0",
"Result": null
Expand Down Expand Up @@ -210,15 +208,13 @@
}
],
"Plan": [
"HashJoin_38 63744383.74 root inner join, equal:[eq(test.t1.b, test.t2.b) eq(test.t1.a, test.t2.a)]",
"├─Selection_64(Build) 7984.01 root eq(cast(test.t2.b, double BINARY), 0), not(isnull(test.t2.a)), not(isnull(test.t2.b))",
"│ └─TableReader_63 7984.01 root data:Selection_62",
"│ └─Selection_62 7984.01 cop[tikv] eq(cast(test.t2.b, double BINARY), 0), not(isnull(test.t2.a)), not(isnull(test.t2.b))",
"│ └─TableFullScan_61 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo",
"└─Selection_55(Probe) 7984.01 root eq(cast(test.t1.b, double BINARY), 0), not(isnull(test.t1.a)), not(isnull(test.t1.b))",
" └─TableReader_54 7984.01 root data:Selection_53",
" └─Selection_53 7984.01 cop[tikv] eq(cast(test.t1.b, double BINARY), 0), not(isnull(test.t1.a)), not(isnull(test.t1.b))",
" └─TableFullScan_52 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"HashJoin_36 124.88 root inner join, equal:[eq(test.t1.a, test.t2.a)]",
"├─IndexLookUp_57(Build) 99.90 root ",
"│ ├─IndexRangeScan_55(Build) 99.90 cop[tikv] table:t2, index:b(b, a) range:[0 -inf,0 +inf], keep order:false, stats:pseudo",
"│ └─TableRowIDScan_56(Probe) 99.90 cop[tikv] table:t2 keep order:false, stats:pseudo",
"└─IndexLookUp_51(Probe) 99.90 root ",
" ├─IndexRangeScan_49(Build) 99.90 cop[tikv] table:t1, index:b(b, a) range:[0 -inf,0 +inf], keep order:false, stats:pseudo",
" └─TableRowIDScan_50(Probe) 99.90 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"LastPlanUseCache": "0",
"Result": null
Expand Down
17 changes: 14 additions & 3 deletions expression/builtin_compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -1368,17 +1368,28 @@ func RefineComparedConstant(ctx sessionctx.Context, targetFieldType types.FieldT
// refineArgs will rewrite the arguments if the compare expression is `int column <cmp> non-int constant` or
// `non-int constant <cmp> int column`. E.g., `a < 1.1` will be rewritten to `a < 2`. It also handles comparing year type
// with int constant if the int constant falls into a sensible year representation.
// This refine operation depends on the values of these args, but these values can change when using plan-cache.
// So we have to skip this operation or mark the plan as over-optimized when using plan-cache.
func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Expression) []Expression {
if MaybeOverOptimized4PlanCache(ctx, args) {
return args
}
arg0Type, arg1Type := args[0].GetType(), args[1].GetType()
arg0IsInt := arg0Type.EvalType() == types.ETInt
arg1IsInt := arg1Type.EvalType() == types.ETInt
arg0IsString := arg0Type.EvalType() == types.ETString
arg1IsString := arg1Type.EvalType() == types.ETString
arg0, arg0IsCon := args[0].(*Constant)
arg1, arg1IsCon := args[1].(*Constant)
isExceptional, finalArg0, finalArg1 := false, args[0], args[1]
isPositiveInfinite, isNegativeInfinite := false, false
if MaybeOverOptimized4PlanCache(ctx, args) {
// To keep the result be compatible with MySQL, refine `int non-constant <cmp> str constant`
// here and skip this refine operation in all other cases for safety.
if (arg0IsInt && !arg0IsCon && arg1IsString && arg1IsCon) || (arg1IsInt && !arg1IsCon && arg0IsString && arg0IsCon) {
ctx.GetSessionVars().StmtCtx.MaybeOverOptimized4PlanCache = true
RemoveMutableConst(ctx, args)
} else {
return args
}
}
// int non-constant [cmp] non-int constant
if arg0IsInt && !arg0IsCon && !arg1IsInt && arg1IsCon {
arg1, isExceptional = RefineComparedConstant(ctx, *arg0Type, arg1, c.op)
Expand Down
4 changes: 4 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6298,6 +6298,10 @@ func (s *testIntegrationSerialSuite) TestCacheRefineArgs(c *C) {
tk.MustExec("set @p0='0'")
tk.MustQuery("execute stmt using @p0").Check(testkit.Rows("1"))

tk.MustExec("prepare stmt from 'SELECT UCASE(?) < col_int from t;';")
tk.MustExec("set @a1 = 'xayh7vrWVNqZtzlJmdJQUwAHnkI8Ec';")
tk.MustQuery("execute stmt using @a1;").Check(testkit.Rows("<nil>"))

tk.MustExec("delete from t")
tk.MustExec("insert into t values(1)")
tk.MustExec("prepare stmt from 'SELECT col_int < ? FROM t'")
Expand Down
21 changes: 20 additions & 1 deletion expression/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -909,13 +909,19 @@ func ContainCorrelatedColumn(exprs []Expression) bool {
// `$a==$b`, but it will cause wrong results when `$a!=$b`.
// So we need to do the check here. The check includes the following aspects:
// 1. Whether the plan cache switch is enable.
// 2. Whether the expressions contain a lazy constant.
// 2. Whether the statement can be cached.
// 3. Whether the expressions contain a lazy constant.
// TODO: Do more careful check here.
func MaybeOverOptimized4PlanCache(ctx sessionctx.Context, exprs []Expression) bool {
// If we do not enable plan cache, all the optimization can work correctly.
if !ctx.GetSessionVars().StmtCtx.UseCache {
return false
}
if ctx.GetSessionVars().StmtCtx.MaybeOverOptimized4PlanCache {
// If the current statement can not be cached. We should remove the mutable constant.
RemoveMutableConst(ctx, exprs)
return false
}
return containMutableConst(ctx, exprs)
}

Expand All @@ -936,6 +942,19 @@ func containMutableConst(ctx sessionctx.Context, exprs []Expression) bool {
return false
}

// RemoveMutableConst used to remove the `ParamMarker` and `DeferredExpr` in the `Constant` expr.
func RemoveMutableConst(ctx sessionctx.Context, exprs []Expression) {
for _, expr := range exprs {
switch v := expr.(type) {
case *Constant:
v.ParamMarker = nil
v.DeferredExpr = nil
case *ScalarFunction:
RemoveMutableConst(ctx, v.GetArgs())
}
}
}

const (
_ = iota
kib = 1 << (10 * iota)
Expand Down
13 changes: 11 additions & 2 deletions planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1446,11 +1446,20 @@ func (er *expressionRewriter) inToExpression(lLen int, not bool, tp *types.Field
er.ctxStackAppend(expression.NewNull(), types.EmptyName)
return
}
maybeOverOptimized := expression.MaybeOverOptimized4PlanCache(er.sctx, args)
if !maybeOverOptimized && leftEt == types.ETInt {
if leftEt == types.ETInt {
for i := 1; i < len(args); i++ {
if c, ok := args[i].(*expression.Constant); ok {
var isExceptional bool
if expression.MaybeOverOptimized4PlanCache(er.sctx, []expression.Expression{c}) {
if c.GetType().EvalType() == types.ETString {
// To keep the result be compatible with MySQL, refine `int non-constant <cmp> str constant`
// here and skip this refine operation in all other cases for safety.
er.sctx.GetSessionVars().StmtCtx.MaybeOverOptimized4PlanCache = true
expression.RemoveMutableConst(er.sctx, []expression.Expression{c})
} else {
continue
}
}
args[i], isExceptional = expression.RefineComparedConstant(er.sctx, *leftFt, c, opcode.EQ)
if isExceptional {
args[i] = c
Expand Down
46 changes: 46 additions & 0 deletions planner/core/prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,52 @@ func (s *testPlanSerialSuite) TestIssue28867(c *C) {
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1"))
}

func (s *testPlanSerialSuite) TestIssue28828(c *C) {
store, dom, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
tk := testkit.NewTestKit(c, store)
defer func() {
dom.Close()
store.Close()
}()
orgEnable := core.PreparedPlanCacheEnabled()
defer func() {
core.SetPreparedPlanCache(orgEnable)
}()
core.SetPreparedPlanCache(true)
tk.MustExec("use test")
tk.MustExec("set @@tidb_enable_collect_execution_info=0;")
tk.MustExec("CREATE TABLE t (" +
"id bigint(20) NOT NULL," +
"audit_id bigint(20) NOT NULL," +
"PRIMARY KEY (id) /*T![clustered_index] CLUSTERED */," +
"KEY index_audit_id (audit_id)" +
");")
tk.MustExec("insert into t values(1,9941971237863475), (2,9941971237863476), (3, 0);")
tk.MustExec("prepare stmt from 'select * from t where audit_id=?';")
tk.MustExec("set @a='9941971237863475', @b=9941971237863475, @c='xayh7vrWVNqZtzlJmdJQUwAHnkI8Ec', @d='0.0', @e='0.1', @f = '9941971237863476';")

tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1 9941971237863475"))
tk.MustQuery("execute stmt using @b;").Check(testkit.Rows("1 9941971237863475"))
// When the type of parameters have been changed, the plan cache can not be used.
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @c;").Check(testkit.Rows("3 0"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @d;").Check(testkit.Rows("3 0"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @e;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @d;").Check(testkit.Rows("3 0"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @f;").Check(testkit.Rows("2 9941971237863476"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustExec("prepare stmt from 'select count(*) from t where audit_id in (?, ?, ?, ?, ?)';")
tk.MustQuery("execute stmt using @a, @b, @c, @d, @e;").Check(testkit.Rows("2"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @f, @b, @c, @d, @e;").Check(testkit.Rows("3"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
}

func (s *testPlanSerialSuite) TestIssue28920(c *C) {
store, dom, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
Expand Down