Skip to content

Commit

Permalink
planner: record reasons when skipping Plan Cache (#40210)
Browse files Browse the repository at this point in the history
  • Loading branch information
qw4990 authored Dec 28, 2022
1 parent f9af75f commit b196756
Show file tree
Hide file tree
Showing 9 changed files with 20 additions and 23 deletions.
7 changes: 4 additions & 3 deletions expression/builtin_compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -1575,12 +1575,13 @@ func (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Express
// To keep the result be compatible with MySQL, refine `int non-constant <cmp> str constant`
// here and skip this refine operation in all other cases for safety.
if (arg0IsInt && !arg0IsCon && arg1IsString && arg1IsCon) || (arg1IsInt && !arg1IsCon && arg0IsString && arg0IsCon) {
ctx.GetSessionVars().StmtCtx.SkipPlanCache = true
var reason error
if arg1IsString {
ctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg1.String()))
reason = errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg1.String())
} else { // arg0IsString
ctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String()))
reason = errors.Errorf("skip plan-cache: '%v' may be converted to INT", arg0.String())
}
ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(reason)
RemoveMutableConst(ctx, args)
} else {
return args
Expand Down
3 changes: 1 addition & 2 deletions expression/builtin_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ func (c *inFunctionClass) verifyArgs(ctx sessionctx.Context, args []Expression)
case columnType.GetType() == mysql.TypeBit && constant.Value.Kind() == types.KindInt64:
if constant.Value.GetInt64() < 0 {
if MaybeOverOptimized4PlanCache(ctx, args) {
ctx.GetSessionVars().StmtCtx.SkipPlanCache = true
ctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: Bit Column in (%v)", constant.Value.GetInt64()))
ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: Bit Column in (%v)", constant.Value.GetInt64()))
}
continue
}
Expand Down
3 changes: 1 addition & 2 deletions planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1562,8 +1562,7 @@ func (er *expressionRewriter) inToExpression(lLen int, not bool, tp *types.Field
if c.GetType().EvalType() == types.ETString {
// To keep the result be compatible with MySQL, refine `int non-constant <cmp> str constant`
// here and skip this refine operation in all other cases for safety.
er.sctx.GetSessionVars().StmtCtx.SkipPlanCache = true
er.sctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: '%v' may be converted to INT", c.String()))
er.sctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: '%v' may be converted to INT", c.String()))
expression.RemoveMutableConst(er.sctx, []expression.Expression{c})
} else {
continue
Expand Down
3 changes: 1 addition & 2 deletions planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -928,8 +928,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
if len(path.Ranges) == 0 {
// We should uncache the tableDual plan.
if expression.MaybeOverOptimized4PlanCache(ds.ctx, path.AccessConds) {
ds.ctx.GetSessionVars().StmtCtx.SkipPlanCache = true
ds.ctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: get a TableDual plan"))
ds.ctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: get a TableDual plan"))
}
dual := PhysicalTableDual{}.Init(ds.ctx, ds.stats, ds.blockOffset)
dual.SetSchema(ds.schema)
Expand Down
7 changes: 0 additions & 7 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7792,8 +7792,6 @@ func TestPlanCacheForTableRangeFallback(t *testing.T) {
tk.MustExec("set @a=10, @b=20, @c=30, @d=40, @e=50")
tk.MustExec("execute stmt using @a, @b, @c, @d, @e")
tk.MustQuery("show warnings").Sort().Check(testkit.Rows("Warning 1105 Memory capacity of 10 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long"))
tk.MustExec("execute stmt using @a, @b, @c, @d, @e")
// The plan with range fallback is not cached.
Expand Down Expand Up @@ -7842,7 +7840,6 @@ func TestPlanCacheForIndexRangeFallback(t *testing.T) {
tk.MustExec("set @a='aa', @b='bb', @c='cc', @d='dd', @e='ee', @f='ff', @g='gg', @h='hh', @i='ii', @j='jj'")
tk.MustExec("execute stmt2 using @a, @b, @c, @d, @e, @f, @g, @h, @i, @j")
tk.MustQuery("show warnings").Sort().Check(testkit.Rows("Warning 1105 Memory capacity of 1330 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long"))
tk.MustExec("execute stmt2 using @a, @b, @c, @d, @e, @f, @g, @h, @i, @j")
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
Expand Down Expand Up @@ -8000,10 +7997,6 @@ func TestPlanCacheForIndexJoinRangeFallback(t *testing.T) {
tk.MustExec("set @a='a', @b='b', @c='c', @d='d', @e='e'")
tk.MustExec("execute stmt2 using @a, @b, @c, @d, @e")
tk.MustQuery("show warnings").Sort().Check(testkit.Rows("Warning 1105 Memory capacity of 1275 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long",
"Warning 1105 skip plan-cache: in-list is too long"))
tk.MustExec("execute stmt2 using @a, @b, @c, @d, @e")
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
Expand Down
3 changes: 1 addition & 2 deletions planner/core/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,7 @@ func setupFineGrainedShuffleInternal(plan PhysicalPlan, helper *fineGrainedShuff
// Todo: make more careful check here.
func checkPlanCacheable(sctx sessionctx.Context, plan PhysicalPlan) {
if sctx.GetSessionVars().StmtCtx.UseCache && useTiFlash(plan) {
sctx.GetSessionVars().StmtCtx.SkipPlanCache = true
sctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: TiFlash plan is un-cacheable"))
sctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: TiFlash plan is un-cacheable"))
}
}

Expand Down
2 changes: 1 addition & 1 deletion planner/core/plan_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isNonPrepared

// We only cache the tableDual plan when the number of parameters are zero.
if containTableDual(p) && paramNum > 0 {
stmtCtx.SkipPlanCache = true
stmtCtx.SetSkipPlanCache(errors.New("skip plan-cache: get a TableDual plan"))
}
if stmtAst.UseCache && !stmtCtx.SkipPlanCache && !ignorePlanCache {
// rebuild key to exclude kv.TiFlash when stmt is not read only
Expand Down
12 changes: 10 additions & 2 deletions sessionctx/stmtctx/stmtctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,15 @@ func (sc *StatementContext) SetPlanHint(hint string) {
sc.planHint = hint
}

// SetSkipPlanCache sets to skip the plan cache and records the reason.
func (sc *StatementContext) SetSkipPlanCache(reason error) {
if sc.UseCache && sc.SkipPlanCache {
return // avoid unnecessary warnings
}
sc.SkipPlanCache = true
sc.AppendWarning(reason)
}

// TableEntry presents table in db.
type TableEntry struct {
DB string
Expand Down Expand Up @@ -1154,9 +1163,8 @@ func (sc *StatementContext) GetLockWaitStartTime() time.Time {
func (sc *StatementContext) RecordRangeFallback(rangeMaxSize int64) {
// If range fallback happens, it means ether the query is unreasonable(for example, several long IN lists) or tidb_opt_range_max_size is too small
// and the generated plan is probably suboptimal. In that case we don't put it into plan cache.
sc.SkipPlanCache = true
if sc.UseCache {
sc.AppendWarning(errors.Errorf("skip plan-cache: in-list is too long"))
sc.SetSkipPlanCache(errors.Errorf("skip plan-cache: in-list is too long"))
}
if !sc.RangeFallback {
sc.AppendWarning(errors.Errorf("Memory capacity of %v bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen", rangeMaxSize))
Expand Down
3 changes: 1 addition & 2 deletions util/ranger/detacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,7 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex
}
if expression.MaybeOverOptimized4PlanCache(sctx, conditions) {
// `a=@x and a=@y` --> `a=@x if @x==@y`
sctx.GetSessionVars().StmtCtx.SkipPlanCache = true
sctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("skip plan-cache: some parameters may be overwritten"))
sctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("skip plan-cache: some parameters may be overwritten"))
}
}
}
Expand Down

0 comments on commit b196756

Please sign in to comment.