From 3bb2603c558afef45d677154ecbc2dea04c1b43c Mon Sep 17 00:00:00 2001 From: Yuanjia Zhang Date: Wed, 4 Jan 2023 12:52:19 +0800 Subject: [PATCH 1/3] This is an automated cherry-pick of #40280 Signed-off-by: ti-chi-bot --- planner/core/plan_cache.go | 32 ++++++++++++++++++++++++++++++-- planner/core/plan_cache_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index 24f7af7cd115b..d8072875b5e71 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -126,14 +126,24 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, stmtCtx.UseCache = stmtAst.UseCache var bindSQL string - var ignorePlanCache = false + if stmtCtx.UseCache { + var ignoreByBinding bool + bindSQL, ignoreByBinding = GetBindSQL4PlanCache(sctx, stmt) + if ignoreByBinding { + stmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: ignore plan cache by binding")) + } + } // In rc or for update read, we need the latest schema version to decide whether we need to // rebuild the plan. So we set this value in rc or for update read. In other cases, let it be 0. var latestSchemaVersion int64 +<<<<<<< HEAD if stmtAst.UseCache { bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, stmt) +======= + if stmtCtx.UseCache { +>>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || stmt.ForUpdateRead { // In Rc or ForUpdateRead, we should check if the information schema has been changed since // last time. If it changed, we should rebuild the plan. Here, we use a different and more @@ -148,21 +158,35 @@ 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 { // for point query plan + if plan, names, ok, err := getCachedPointPlan(stmtAst, sessVars, stmtCtx); ok { +>>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) 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 { // for non-point plans + if plan, names, ok, err := getCachedPlan(sctx, isNonPrepared, cacheKey, bindSQL, is, stmt, +>>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) paramTypes); err != nil || ok { return plan, names, err } } +<<<<<<< HEAD return generateNewPlan(ctx, sctx, isGeneralPlanCache, is, stmt, ignorePlanCache, cacheKey, latestSchemaVersion, paramNum, paramTypes, bindSQL) +======= + return generateNewPlan(ctx, sctx, isNonPrepared, is, stmt, cacheKey, latestSchemaVersion, paramNum, paramTypes, bindSQL) +>>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) } // parseParamTypes get parameters' types in PREPARE statement @@ -253,8 +277,12 @@ func getGeneralPlan(sctx sessionctx.Context, isGeneralPlanCache bool, cacheKey k // generateNewPlan call the optimizer to generate a new plan for current statement // and try to add it to cache +<<<<<<< HEAD func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlanCache bool, is infoschema.InfoSchema, stmt *PlanCacheStmt, ignorePlanCache bool, cacheKey kvcache.Key, latestSchemaVersion int64, paramNum int, +======= +func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isNonPrepared bool, is infoschema.InfoSchema, stmt *PlanCacheStmt, cacheKey kvcache.Key, latestSchemaVersion int64, paramNum int, +>>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) paramTypes []*types.FieldType, bindSQL string) (Plan, []*types.FieldName, error) { stmtAst := stmt.PreparedAst sessVars := sctx.GetSessionVars() @@ -276,7 +304,7 @@ func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlan if containTableDual(p) && paramNum > 0 { stmtCtx.SetSkipPlanCache(errors.New("skip plan-cache: get a TableDual plan")) } - if stmtCtx.UseCache && !ignorePlanCache { + if stmtCtx.UseCache { // rebuild key to exclude kv.TiFlash when stmt is not read only if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(stmtAst.Stmt, sessVars) { delete(sessVars.IsolationReadEngines, kv.TiFlash) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index c678209dbe1ec..17b41e43e3d5e 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -314,7 +314,37 @@ 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) { +======= +func TestIssue40225(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t (a int, key(a))") + tk.MustExec("prepare st from 'select * from t where a INT) since plan-cache is totally disabled. + + tk.MustExec("prepare st from 'select * from t where a>?'") + tk.MustExec("set @a=1") + tk.MustExec("execute st using @a") + tk.MustExec("execute st using @a") + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("1")) + tk.MustExec("create binding for select * from t where a>1 using select /*+ ignore_plan_cache() */ * from t where a>1") + tk.MustExec("execute st using @a") + tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) + tk.MustExec("execute st using @a") + tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1")) +} + +func TestUncacheableReason(t *testing.T) { +>>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec("use test") From 04824410af1749688f6ebda0b8b1b0ca324d0b0b Mon Sep 17 00:00:00 2001 From: qw4990 Date: Wed, 15 Feb 2023 17:25:43 +0800 Subject: [PATCH 2/3] fixup --- planner/core/plan_cache.go | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index d8072875b5e71..95e8903cfbf39 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -138,12 +138,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 -<<<<<<< HEAD - if stmtAst.UseCache { - bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, stmt) -======= if stmtCtx.UseCache { ->>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || stmt.ForUpdateRead { // In Rc or ForUpdateRead, we should check if the information schema has been changed since // last time. If it changed, we should rebuild the plan. Here, we use a different and more @@ -158,35 +153,20 @@ 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 { // for point query plan - if plan, names, ok, err := getCachedPointPlan(stmtAst, sessVars, stmtCtx); ok { ->>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) + if plan, names, ok, err := getPointQueryPlan(stmtAst, sessVars, stmtCtx); ok { 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 { // for non-point plans - if plan, names, ok, err := getCachedPlan(sctx, isNonPrepared, cacheKey, bindSQL, is, stmt, ->>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) + if plan, names, ok, err := getGeneralPlan(sctx, isGeneralPlanCache, cacheKey, bindSQL, is, stmt, paramTypes); err != nil || ok { return plan, names, err } } -<<<<<<< HEAD - return generateNewPlan(ctx, sctx, isGeneralPlanCache, is, stmt, ignorePlanCache, cacheKey, - latestSchemaVersion, paramNum, paramTypes, bindSQL) -======= - return generateNewPlan(ctx, sctx, isNonPrepared, is, stmt, cacheKey, latestSchemaVersion, paramNum, paramTypes, bindSQL) ->>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) + return generateNewPlan(ctx, sctx, isGeneralPlanCache, is, stmt, cacheKey, latestSchemaVersion, paramNum, paramTypes, bindSQL) } // parseParamTypes get parameters' types in PREPARE statement @@ -277,12 +257,7 @@ func getGeneralPlan(sctx sessionctx.Context, isGeneralPlanCache bool, cacheKey k // generateNewPlan call the optimizer to generate a new plan for current statement // and try to add it to cache -<<<<<<< HEAD -func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlanCache bool, is infoschema.InfoSchema, stmt *PlanCacheStmt, - ignorePlanCache bool, cacheKey kvcache.Key, latestSchemaVersion int64, paramNum int, -======= -func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isNonPrepared bool, is infoschema.InfoSchema, stmt *PlanCacheStmt, cacheKey kvcache.Key, latestSchemaVersion int64, paramNum int, ->>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) +func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlanCache bool, is infoschema.InfoSchema, stmt *PlanCacheStmt, cacheKey kvcache.Key, latestSchemaVersion int64, paramNum int, paramTypes []*types.FieldType, bindSQL string) (Plan, []*types.FieldName, error) { stmtAst := stmt.PreparedAst sessVars := sctx.GetSessionVars() From b8ad5fb675477c00eaf4e1095001066c2a86c30e Mon Sep 17 00:00:00 2001 From: qw4990 Date: Wed, 15 Feb 2023 17:26:14 +0800 Subject: [PATCH 3/3] fixup --- planner/core/plan_cache_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/planner/core/plan_cache_test.go b/planner/core/plan_cache_test.go index 17b41e43e3d5e..ba3e8962ff229 100644 --- a/planner/core/plan_cache_test.go +++ b/planner/core/plan_cache_test.go @@ -314,9 +314,6 @@ 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) { -======= func TestIssue40225(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) @@ -343,8 +340,7 @@ func TestIssue40225(t *testing.T) { tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1")) } -func TestUncacheableReason(t *testing.T) { ->>>>>>> 7fafb6db45d (planner: better coordination between the ignore_plan_cache() binding and plan-cache (#40280)) +func TestIssue40224(t *testing.T) { store := testkit.CreateMockStore(t) tk := testkit.NewTestKit(t, store) tk.MustExec("use test")