Skip to content

Commit

Permalink
cherry pick pingcap#36427 to release-6.1
Browse files Browse the repository at this point in the history
Signed-off-by: ti-srebot <[email protected]>
  • Loading branch information
fzzf678 authored and ti-srebot committed Aug 19, 2022
1 parent 46ebd96 commit 5a6afcb
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 10 deletions.
55 changes: 55 additions & 0 deletions executor/explainfor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,61 @@ func TestHint4PlanCache(t *testing.T) {
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
}

func TestIgnorePlanCacheWithPrepare(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec("drop table if exists t;")
tk.MustExec("create table t(a int, index idx_a(a));")
tk.MustExec("drop table if exists r;")
tk.MustExec("create table r(a int);")

// test use_index
tk.MustExec("prepare stmt from 'select * from t;';")
tk.MustExec("create binding for select * from t using select /*+ use_index(t, idx_a) */ * from t;")
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_binding;").Check(testkit.Rows("1"))

tk.MustExec("create binding for select * from t using select /*+ ignore_plan_cache() */ * from t;")
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_binding;").Check(testkit.Rows("1"))

tk.MustExec("create binding for select * from t using select /*+ use_index(t, idx_a) */ * from t;")
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_binding;").Check(testkit.Rows("1"))

// test straight_join
tk.MustExec("prepare stmt_join from 'select * from t, r where r.a = t.a;';")
tk.MustExec("create binding for select * from t, r where r.a = t.a using select /*+ straight_join() */* from t, r where r.a = t.a;")
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_binding;").Check(testkit.Rows("1"))

tk.MustExec("create binding for select * from t, r where r.a = t.a using select /*+ ignore_plan_cache() */* from t, r where r.a = t.a;")
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_binding;").Check(testkit.Rows("1"))

tk.MustExec("create binding for select * from t, r where r.a = t.a using select /*+ straight_join() */* from t, r where r.a = t.a;")
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
tk.MustQuery("execute stmt_join;").Check(testkit.Rows())
tk.MustQuery("select @@last_plan_from_binding;").Check(testkit.Rows("1"))

}

func TestSelectView4PlanCache(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
Expand Down
42 changes: 32 additions & 10 deletions planner/core/common_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,34 +413,37 @@ func (e *Execute) setFoundInPlanCache(sctx sessionctx.Context, opt bool) error {
}

// GetBindSQL4PlanCache used to get the bindSQL for plan cache to build the plan cache key.
func GetBindSQL4PlanCache(sctx sessionctx.Context, preparedStmt *CachedPrepareStmt) string {
func GetBindSQL4PlanCache(sctx sessionctx.Context, preparedStmt *CachedPrepareStmt) (string, bool) {
useBinding := sctx.GetSessionVars().UsePlanBaselines
ignore := false
if !useBinding || preparedStmt.PreparedAst.Stmt == nil || preparedStmt.NormalizedSQL4PC == "" || preparedStmt.SQLDigest4PC == "" {
return ""
return "", ignore
}
if sctx.Value(bindinfo.SessionBindInfoKeyType) == nil {
return ""
return "", ignore
}
sessionHandle := sctx.Value(bindinfo.SessionBindInfoKeyType).(*bindinfo.SessionHandle)
bindRecord := sessionHandle.GetBindRecord(preparedStmt.SQLDigest4PC, preparedStmt.NormalizedSQL4PC, "")
if bindRecord != nil {
enabledBinding := bindRecord.FindEnabledBinding()
if enabledBinding != nil {
return enabledBinding.BindSQL
ignore = enabledBinding.Hint.ContainTableHint(HintIgnorePlanCache)
return enabledBinding.BindSQL, ignore
}
}
globalHandle := domain.GetDomain(sctx).BindHandle()
if globalHandle == nil {
return ""
return "", ignore
}
bindRecord = globalHandle.GetBindRecord(preparedStmt.SQLDigest4PC, preparedStmt.NormalizedSQL4PC, "")
if bindRecord != nil {
enabledBinding := bindRecord.FindEnabledBinding()
if enabledBinding != nil {
return enabledBinding.BindSQL
ignore = enabledBinding.Hint.ContainTableHint(HintIgnorePlanCache)
return enabledBinding.BindSQL, ignore
}
}
return ""
return "", ignore
}

func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt) (err error) {
Expand All @@ -451,9 +454,28 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
stmtCtx.UseCache = prepared.UseCache

var bindSQL string
<<<<<<< HEAD
if prepared.UseCache {
bindSQL = GetBindSQL4PlanCache(sctx, preparedStmt)
if cacheKey, err = NewPlanCacheKey(sctx.GetSessionVars(), preparedStmt.StmtText, preparedStmt.StmtDB, prepared.SchemaVersion); err != nil {
=======
var ignorePlanCache = false

// 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

if prepared.UseCache {
bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, preparedStmt)
if sctx.GetSessionVars().IsIsolation(ast.ReadCommitted) || preparedStmt.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
// up-to-date schema version which can lead plan cache miss and thus, the plan will be rebuilt.
latestSchemaVersion = domain.GetDomain(sctx).InfoSchema().SchemaMetaVersion()
}
if cacheKey, err = NewPlanCacheKey(sctx.GetSessionVars(), preparedStmt.StmtText,
preparedStmt.StmtDB, prepared.SchemaVersion, latestSchemaVersion); err != nil {
>>>>>>> 1923d3362... planner: fix bindings with ignore_plan_cache_hint cannot work (#36427)
return err
}
}
Expand All @@ -479,7 +501,7 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
}
}

if prepared.UseCache && prepared.CachedPlan != nil { // short path for point-get plans
if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // short path for point-get plans
// Rewriting the expression in the select.where condition will convert its
// type from "paramMarker" to "Constant".When Point Select queries are executed,
// the expression in the where condition will not be evaluated,
Expand All @@ -505,7 +527,7 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
stmtCtx.PointExec = true
return nil
}
if prepared.UseCache { // for general plans
if prepared.UseCache && !ignorePlanCache { // for general plans
if cacheValue, exists := sctx.PreparedPlanCache().Get(cacheKey); exists {
if err := e.checkPreparedPriv(ctx, sctx, preparedStmt, is); err != nil {
return err
Expand Down Expand Up @@ -582,7 +604,7 @@ REBUILD:
if containTableDual(p) && varsNum > 0 {
stmtCtx.SkipPlanCache = true
}
if prepared.UseCache && !stmtCtx.SkipPlanCache {
if prepared.UseCache && !stmtCtx.SkipPlanCache && !ignorePlanCache {
// rebuild key to exclude kv.TiFlash when stmt is not read only
if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(stmt, sessVars) {
delete(sessVars.IsolationReadEngines, kv.TiFlash)
Expand Down

0 comments on commit 5a6afcb

Please sign in to comment.