Skip to content

Commit

Permalink
planner: fix bindings with ignore_plan_cache_hint cannot work (#36427) (
Browse files Browse the repository at this point in the history
#37231)

close #34596
  • Loading branch information
ti-srebot authored Aug 22, 2022
1 parent 6d0585b commit 2851720
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 12 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
30 changes: 18 additions & 12 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,12 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
stmtCtx.UseCache = prepared.UseCache

var bindSQL string
var ignorePlanCache = false

if prepared.UseCache {
bindSQL = GetBindSQL4PlanCache(sctx, preparedStmt)
if cacheKey, err = NewPlanCacheKey(sctx.GetSessionVars(), preparedStmt.StmtText, preparedStmt.StmtDB, prepared.SchemaVersion); err != nil {
bindSQL, ignorePlanCache = GetBindSQL4PlanCache(sctx, preparedStmt)
if cacheKey, err = NewPlanCacheKey(sctx.GetSessionVars(), preparedStmt.StmtText,
preparedStmt.StmtDB, prepared.SchemaVersion); err != nil {
return err
}
}
Expand All @@ -479,7 +485,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 +511,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 +588,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 2851720

Please sign in to comment.