From 0c4f5eb312c8cde5e57b34db9ca1ad1cdf5c0516 Mon Sep 17 00:00:00 2001 From: qw4990 Date: Fri, 30 Dec 2022 15:20:52 +0800 Subject: [PATCH 1/5] fixup --- parser/ast/misc.go | 1 - planner/core/plan_cache.go | 10 +++++----- planner/core/plan_cache_utils.go | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/parser/ast/misc.go b/parser/ast/misc.go index 7a0e2fc7a1a50..bfa105365700d 100644 --- a/parser/ast/misc.go +++ b/parser/ast/misc.go @@ -520,7 +520,6 @@ type Prepared struct { StmtType string Params []ParamMarkerExpr SchemaVersion int64 - UseCache bool CachedPlan interface{} CachedNames interface{} } diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index 8036f4067ce65..9222f7551fc49 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -100,7 +100,7 @@ func planCachePreprocess(ctx context.Context, sctx sessionctx.Context, isNonPrep // So we need to clear the current session's plan cache. // And update lastUpdateTime to the newest one. expiredTimeStamp4PC := domain.GetDomain(sctx).ExpiredTimeStamp4PC() - if stmtAst.UseCache && expiredTimeStamp4PC.Compare(vars.LastUpdateTime4PC) > 0 { + if stmt.StmtCacheable && expiredTimeStamp4PC.Compare(vars.LastUpdateTime4PC) > 0 { sctx.GetPlanCache(isNonPrepared).DeleteAll() stmtAst.CachedPlan = nil vars.LastUpdateTime4PC = expiredTimeStamp4PC @@ -127,7 +127,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, sessVars := sctx.GetSessionVars() stmtCtx := sessVars.StmtCtx stmtAst := stmt.PreparedAst - stmtCtx.UseCache = stmtAst.UseCache + stmtCtx.UseCache = stmt.StmtCacheable var bindSQL string var ignorePlanCache = false @@ -136,7 +136,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, // rebuild the plan. So we set this value in rc or for update read. In other cases, let it be 0. var latestSchemaVersion int64 - if stmtAst.UseCache { + if stmtCtx.UseCache { bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, stmt) if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || stmt.ForUpdateRead { // In Rc or ForUpdateRead, we should check if the information schema has been changed since @@ -152,13 +152,13 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, paramNum, paramTypes := parseParamTypes(sctx, params) - if stmtAst.UseCache && stmtAst.CachedPlan != nil && !ignorePlanCache { // for point query plan + if stmtCtx.UseCache && stmtAst.CachedPlan != nil && !ignorePlanCache { // for point query plan if plan, names, ok, err := getCachedPointPlan(stmtAst, sessVars, stmtCtx); ok { return plan, names, err } } - if stmtAst.UseCache && !ignorePlanCache { // for non-point plans + if stmtCtx.UseCache && !ignorePlanCache { // for non-point plans if plan, names, ok, err := getCachedPlan(sctx, isNonPrepared, cacheKey, bindSQL, is, stmt, paramTypes); err != nil || ok { return plan, names, err diff --git a/planner/core/plan_cache_utils.go b/planner/core/plan_cache_utils.go index 6408d269ef799..3fe4ee38bfe45 100644 --- a/planner/core/plan_cache_utils.go +++ b/planner/core/plan_cache_utils.go @@ -119,12 +119,14 @@ func GeneratePlanCacheStmtWithAST(ctx context.Context, sctx sessionctx.Context, var ( normalizedSQL4PC, digest4PC string selectStmtNode ast.StmtNode + cacheable bool + reason string ) if !vars.EnablePreparedPlanCache { - prepared.UseCache = false + cacheable = false + reason = "plan cache is disabled" } else { - cacheable, reason := CacheableWithCtx(sctx, paramStmt, ret.InfoSchema) - prepared.UseCache = cacheable + cacheable, reason = CacheableWithCtx(sctx, paramStmt, ret.InfoSchema) if !cacheable { sctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: " + reason)) } @@ -160,6 +162,8 @@ func GeneratePlanCacheStmtWithAST(ctx context.Context, sctx sessionctx.Context, SnapshotTSEvaluator: ret.SnapshotTSEvaluator, NormalizedSQL4PC: normalizedSQL4PC, SQLDigest4PC: digest4PC, + StmtCacheable: cacheable, + UncacheableReason: reason, } if err = CheckPreparedPriv(sctx, preparedObj, ret.InfoSchema); err != nil { return nil, nil, 0, err @@ -412,7 +416,11 @@ type PlanCacheStmt struct { // Executor is only used for point get scene. // Notice that we should only cache the PointGetExecutor that have a snapshot with MaxTS in it. // If the current plan is not PointGet or does not use MaxTS optimization, this value should be nil here. - Executor interface{} + Executor interface{} + + StmtCacheable bool // Whether this stmt is cacheable. + UncacheableReason string // Why this stmt is uncacheable. + NormalizedSQL string NormalizedPlan string SQLDigest *parser.Digest From 89a75eb895474ab3b5cacfab4a3d3374b8b8f6c4 Mon Sep 17 00:00:00 2001 From: qw4990 Date: Fri, 30 Dec 2022 15:21:59 +0800 Subject: [PATCH 2/5] fixup --- planner/core/plan_cache.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index 9222f7551fc49..84be5bcaf9ab9 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -128,6 +128,9 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, stmtCtx := sessVars.StmtCtx stmtAst := stmt.PreparedAst stmtCtx.UseCache = stmt.StmtCacheable + if !stmt.StmtCacheable { + stmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: %s", stmt.UncacheableReason)) + } var bindSQL string var ignorePlanCache = false From 87a0f2aa99eed889d512bc8f0469fc1869afced7 Mon Sep 17 00:00:00 2001 From: qw4990 Date: Fri, 30 Dec 2022 15:24:35 +0800 Subject: [PATCH 3/5] fixup --- planner/core/plan_cache_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index e25565a110e08..b9882c5c96dd0 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -384,3 +384,18 @@ func TestPlanCacheDiagInfo(t *testing.T) { tk.MustExec("execute stmt using @a, @b") // a=1 and a=1 -> a=1 tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: some parameters may be overwritten")) } + +func TestUncacheableReason(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("prepare st from 'select * from t limit ?'") + tk.MustQuery("show warnings").Check(testkit.Rows()) + + tk.MustExec("set @a=1") + tk.MustQuery("execute st using @a").Check(testkit.Rows()) + tk.MustExec("prepare st from 'select * from t limit ?'") + tk.MustQuery("show warnings").Check(testkit.Rows()) +} From 508eee55a3623a11c40a25e3b8df1bed53d9add8 Mon Sep 17 00:00:00 2001 From: qw4990 Date: Fri, 30 Dec 2022 15:27:29 +0800 Subject: [PATCH 4/5] fixup --- planner/core/plan_cache_test.go | 5 +++-- planner/core/prepare_test.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index b9882c5c96dd0..4fe0e6cf153dd 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -392,10 +392,11 @@ func TestUncacheableReason(t *testing.T) { tk.MustExec("create table t (a int)") tk.MustExec("prepare st from 'select * from t limit ?'") - tk.MustQuery("show warnings").Check(testkit.Rows()) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: query has 'limit ?' is un-cacheable")) tk.MustExec("set @a=1") tk.MustQuery("execute st using @a").Check(testkit.Rows()) tk.MustExec("prepare st from 'select * from t limit ?'") - tk.MustQuery("show warnings").Check(testkit.Rows()) + // show the corresponding un-cacheable reason at execute-stage as well + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: query has 'limit ?' is un-cacheable")) } diff --git a/planner/core/prepare_test.go b/planner/core/prepare_test.go index 71eb4c997211d..656aed73ca189 100644 --- a/planner/core/prepare_test.go +++ b/planner/core/prepare_test.go @@ -60,7 +60,7 @@ func TestPointGetPreparedPlan4PlanCache(t *testing.T) { pspk1Id, _, _, err := tk1.Session().PrepareStmt("select * from t where a = ?") require.NoError(t, err) - tk1.Session().GetSessionVars().PreparedStmts[pspk1Id].(*core.PlanCacheStmt).PreparedAst.UseCache = false + tk1.Session().GetSessionVars().PreparedStmts[pspk1Id].(*core.PlanCacheStmt).StmtCacheable = false ctx := context.Background() // first time plan generated From 78f7374717f8ca66a62b7938e5130a5bb4d0492f Mon Sep 17 00:00:00 2001 From: qw4990 Date: Tue, 3 Jan 2023 14:38:21 +0800 Subject: [PATCH 5/5] fixup --- executor/executor_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index 858a4cc9372f9..9b602d2c151f9 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -3621,10 +3621,10 @@ func TestPointGetPreparedPlan(t *testing.T) { pspk1Id, _, _, err := tk.Session().PrepareStmt("select * from t where a = ?") require.NoError(t, err) - tk.Session().GetSessionVars().PreparedStmts[pspk1Id].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk.Session().GetSessionVars().PreparedStmts[pspk1Id].(*plannercore.PlanCacheStmt).StmtCacheable = false pspk2Id, _, _, err := tk.Session().PrepareStmt("select * from t where ? = a ") require.NoError(t, err) - tk.Session().GetSessionVars().PreparedStmts[pspk2Id].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk.Session().GetSessionVars().PreparedStmts[pspk2Id].(*plannercore.PlanCacheStmt).StmtCacheable = false ctx := context.Background() // first time plan generated @@ -3664,7 +3664,7 @@ func TestPointGetPreparedPlan(t *testing.T) { // unique index psuk1Id, _, _, err := tk.Session().PrepareStmt("select * from t where b = ? ") require.NoError(t, err) - tk.Session().GetSessionVars().PreparedStmts[psuk1Id].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk.Session().GetSessionVars().PreparedStmts[psuk1Id].(*plannercore.PlanCacheStmt).StmtCacheable = false rs, err = tk.Session().ExecutePreparedStmt(ctx, psuk1Id, expression.Args2Expressions4Test(1)) require.NoError(t, err) @@ -3782,7 +3782,7 @@ func TestPointGetPreparedPlanWithCommitMode(t *testing.T) { pspk1Id, _, _, err := tk1.Session().PrepareStmt("select * from t where a = ?") require.NoError(t, err) - tk1.Session().GetSessionVars().PreparedStmts[pspk1Id].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk1.Session().GetSessionVars().PreparedStmts[pspk1Id].(*plannercore.PlanCacheStmt).StmtCacheable = false ctx := context.Background() // first time plan generated @@ -3848,11 +3848,11 @@ func TestPointUpdatePreparedPlan(t *testing.T) { updateID1, pc, _, err := tk.Session().PrepareStmt(`update t set c = c + 1 where a = ?`) require.NoError(t, err) - tk.Session().GetSessionVars().PreparedStmts[updateID1].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk.Session().GetSessionVars().PreparedStmts[updateID1].(*plannercore.PlanCacheStmt).StmtCacheable = false require.Equal(t, 1, pc) updateID2, pc, _, err := tk.Session().PrepareStmt(`update t set c = c + 2 where ? = a`) require.NoError(t, err) - tk.Session().GetSessionVars().PreparedStmts[updateID2].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk.Session().GetSessionVars().PreparedStmts[updateID2].(*plannercore.PlanCacheStmt).StmtCacheable = false require.Equal(t, 1, pc) ctx := context.Background() @@ -3887,7 +3887,7 @@ func TestPointUpdatePreparedPlan(t *testing.T) { // unique index updUkID1, _, _, err := tk.Session().PrepareStmt(`update t set c = c + 10 where b = ?`) require.NoError(t, err) - tk.Session().GetSessionVars().PreparedStmts[updUkID1].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk.Session().GetSessionVars().PreparedStmts[updUkID1].(*plannercore.PlanCacheStmt).StmtCacheable = false rs, err = tk.Session().ExecutePreparedStmt(ctx, updUkID1, expression.Args2Expressions4Test(3)) require.Nil(t, rs) require.NoError(t, err) @@ -3956,7 +3956,7 @@ func TestPointUpdatePreparedPlanWithCommitMode(t *testing.T) { ctx := context.Background() updateID1, _, _, err := tk1.Session().PrepareStmt(`update t set c = c + 1 where a = ?`) - tk1.Session().GetSessionVars().PreparedStmts[updateID1].(*plannercore.PlanCacheStmt).PreparedAst.UseCache = false + tk1.Session().GetSessionVars().PreparedStmts[updateID1].(*plannercore.PlanCacheStmt).StmtCacheable = false require.NoError(t, err) // first time plan generated