diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 4411f4b6b90ff..4ffd0a3dbe6be 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -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 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 diff --git a/expression/builtin_other.go b/expression/builtin_other.go index c62278c2bd101..c5bd6738aa9df 100644 --- a/expression/builtin_other.go +++ b/expression/builtin_other.go @@ -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 } diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index ddb905dc5c06b..2694d81ef0a65 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -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 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 diff --git a/planner/core/find_best_task.go b/planner/core/find_best_task.go index f14e343610b5d..ab120d452ac1c 100644 --- a/planner/core/find_best_task.go +++ b/planner/core/find_best_task.go @@ -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) diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 743c6b87dc6d0..31cd5aa9c346b 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -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. @@ -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")) @@ -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")) diff --git a/planner/core/optimizer.go b/planner/core/optimizer.go index 1064ea529b2d0..1a3e1ea5ab821 100644 --- a/planner/core/optimizer.go +++ b/planner/core/optimizer.go @@ -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")) } } diff --git a/planner/core/plan_cache.go b/planner/core/plan_cache.go index ab4eb4e4912ab..9739a63f2b8ff 100644 --- a/planner/core/plan_cache.go +++ b/planner/core/plan_cache.go @@ -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 diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 799f2f8bdeea8..cfe017c7c8805 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -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 @@ -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)) diff --git a/util/ranger/detacher.go b/util/ranger/detacher.go index 596d27c27d9d8..e4d75711cae2a 100644 --- a/util/ranger/detacher.go +++ b/util/ranger/detacher.go @@ -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")) } } }