From 202fe313d280a5394d4b6e4685dd34e223e3e52e Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Tue, 3 Jan 2023 17:30:20 +0800 Subject: [PATCH] This is an automated cherry-pick of #40256 Signed-off-by: ti-chi-bot --- executor/executor_test.go | 16 ++++++++-------- parser/ast/misc.go | 1 - planner/core/plan_cache.go | 22 ++++++++++++++++++++-- planner/core/plan_cache_test.go | 17 +++++++++++++++++ planner/core/plan_cache_utils.go | 26 +++++++++++++++++++++++++- planner/core/prepare_test.go | 2 +- 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index fcb70b1525eaa..9d71b7d29aa9a 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -3587,10 +3587,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 @@ -3630,7 +3630,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) @@ -3748,7 +3748,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 @@ -3814,11 +3814,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() @@ -3853,7 +3853,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) @@ -3922,7 +3922,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 diff --git a/parser/ast/misc.go b/parser/ast/misc.go index 13e71ee12511b..0786a86c3dbee 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 e58e8b6d91708..83f43d22ae401 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -100,8 +100,13 @@ func planCachePreprocess(ctx context.Context, sctx sessionctx.Context, isGeneral // So we need to clear the current session's plan cache. // And update lastUpdateTime to the newest one. expiredTimeStamp4PC := domain.GetDomain(sctx).ExpiredTimeStamp4PC() +<<<<<<< HEAD if stmtAst.UseCache && expiredTimeStamp4PC.Compare(vars.LastUpdateTime4PC) > 0 { sctx.GetPlanCache(isGeneralPlanCache).DeleteAll() +======= + if stmt.StmtCacheable && expiredTimeStamp4PC.Compare(vars.LastUpdateTime4PC) > 0 { + sctx.GetPlanCache(isNonPrepared).DeleteAll() +>>>>>>> 5327d07afc7 (planner: refactor plan-cache UseCache flag (#40256)) stmtAst.CachedPlan = nil vars.LastUpdateTime4PC = expiredTimeStamp4PC } @@ -123,7 +128,10 @@ 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 + if !stmt.StmtCacheable { + stmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: %s", stmt.UncacheableReason)) + } var bindSQL string var ignorePlanCache = false @@ -132,7 +140,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 @@ -148,14 +156,24 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, paramNum, paramTypes := parseParamTypes(sctx, params) +<<<<<<< HEAD if stmtAst.UseCache && stmtAst.CachedPlan != nil && !ignorePlanCache { // for point query plan if plan, names, ok, err := getPointQueryPlan(stmtAst, sessVars, stmtCtx); ok { +======= + if stmtCtx.UseCache && stmtAst.CachedPlan != nil && !ignorePlanCache { // for point query plan + if plan, names, ok, err := getCachedPointPlan(stmtAst, sessVars, stmtCtx); ok { +>>>>>>> 5327d07afc7 (planner: refactor plan-cache UseCache flag (#40256)) return plan, names, err } } +<<<<<<< HEAD if stmtAst.UseCache && !ignorePlanCache { // for general plans if plan, names, ok, err := getGeneralPlan(sctx, isGeneralPlanCache, cacheKey, bindSQL, is, stmt, +======= + if stmtCtx.UseCache && !ignorePlanCache { // for non-point plans + if plan, names, ok, err := getCachedPlan(sctx, isNonPrepared, cacheKey, bindSQL, is, stmt, +>>>>>>> 5327d07afc7 (planner: refactor plan-cache UseCache flag (#40256)) paramTypes); err != nil || ok { return plan, names, err } diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index c678209dbe1ec..40a44e3b1d1bd 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -314,6 +314,7 @@ func TestPlanCacheDiagInfo(t *testing.T) { tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 skip plan-cache: some parameters may be overwritten")) } +<<<<<<< HEAD func TestIssue40224(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) @@ -344,4 +345,20 @@ func TestIssue40224(t *testing.T) { {"IndexReader_6"}, {"└─IndexRangeScan_5"}, // range scan not full scan }) +======= +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("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 ?'") + // 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")) +>>>>>>> 5327d07afc7 (planner: refactor plan-cache UseCache flag (#40256)) } diff --git a/planner/core/plan_cache_utils.go b/planner/core/plan_cache_utils.go index 4229e2b134f06..8cf1b6468ef5b 100644 --- a/planner/core/plan_cache_utils.go +++ b/planner/core/plan_cache_utils.go @@ -113,12 +113,19 @@ 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 { +<<<<<<< HEAD cacheable, reason := CacheableWithCtx(sctx, stmt, ret.InfoSchema) prepared.UseCache = cacheable +======= + cacheable, reason = CacheableWithCtx(sctx, paramStmt, ret.InfoSchema) +>>>>>>> 5327d07afc7 (planner: refactor plan-cache UseCache flag (#40256)) if !cacheable { sctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: " + reason)) } @@ -154,6 +161,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 @@ -414,11 +423,26 @@ func NewPlanCacheValue(plan Plan, names []*types.FieldName, srcMap map[*model.Ta // PlanCacheStmt store prepared ast from PrepareExec and other related fields type PlanCacheStmt struct { +<<<<<<< HEAD PreparedAst *ast.Prepared StmtDB string // which DB the statement will be processed over VisitInfos []visitInfo ColumnInfos interface{} Executor interface{} +======= + PreparedAst *ast.Prepared + StmtDB string // which DB the statement will be processed over + VisitInfos []visitInfo + ColumnInfos interface{} + // 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{} + + StmtCacheable bool // Whether this stmt is cacheable. + UncacheableReason string // Why this stmt is uncacheable. + +>>>>>>> 5327d07afc7 (planner: refactor plan-cache UseCache flag (#40256)) NormalizedSQL string NormalizedPlan string SQLDigest *parser.Digest diff --git a/planner/core/prepare_test.go b/planner/core/prepare_test.go index f592b9824c255..c5c5f043417ca 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