planner, sessionctx : Add 'last_plan_from_cache' to help know whether sql's plan is from plan cache (#16321)

This commit is contained in:
lawyerphx
2020-04-17 17:15:21 +08:00
committed by GitHub
parent 14a4a4e916
commit ff7413fedb
11 changed files with 98 additions and 6 deletions

View File

@ -1695,6 +1695,8 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
vars.SysErrorCount = errCount
vars.SysWarningCount = warnCount
vars.StmtCtx = sc
vars.PrevFoundInPlanCache = vars.FoundInPlanCache
vars.FoundInPlanCache = false
return
}

View File

@ -15,6 +15,7 @@ package executor
import (
"context"
"fmt"
"strings"
"github.com/pingcap/errors"
@ -173,6 +174,10 @@ func (e *SetExecutor) setSysVariable(name string, v *expression.VarAssignment) e
if name == variable.TxnIsolationOneShot && sessionVars.InTxn() {
return errors.Trace(ErrCantChangeTxCharacteristics)
}
if name == variable.TiDBFoundInPlanCache {
sessionVars.StmtCtx.AppendWarning(fmt.Errorf("Set operation for '%s' will not take effect", variable.TiDBFoundInPlanCache))
return nil
}
err = variable.SetSessionSystemVar(sessionVars, name, value)
if err != nil {
return err

2
go.mod
View File

@ -38,7 +38,7 @@ require (
github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989
github.com/pingcap/kvproto v0.0.0-20200409034505-a5af800ca2ef
github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd
github.com/pingcap/parser v0.0.0-20200410065024-81f3db8e6095
github.com/pingcap/parser v0.0.0-20200413043052-ef80f4de418c
github.com/pingcap/pd/v4 v4.0.0-beta.1.0.20200305072537-61d9f9cc35d3
github.com/pingcap/sysutil v0.0.0-20200408114249-ed3bd6f7fdb1
github.com/pingcap/tidb-tools v4.0.0-beta.1.0.20200306084441-875bd09aa3d5+incompatible

4
go.sum
View File

@ -269,8 +269,8 @@ github.com/pingcap/kvproto v0.0.0-20200409034505-a5af800ca2ef/go.mod h1:IOdRDPLy
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd h1:CV3VsP3Z02MVtdpTMfEgRJ4T9NGgGTxdHpJerent7rM=
github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
github.com/pingcap/parser v0.0.0-20200410065024-81f3db8e6095 h1:DyL/YbS4r89FmiZd3XbUrpMSsVFtpOZzh1busGKytiI=
github.com/pingcap/parser v0.0.0-20200410065024-81f3db8e6095/go.mod h1:9v0Edh8IbgjGYW2ArJr19E+bvL8zKahsFp+ixWeId+4=
github.com/pingcap/parser v0.0.0-20200413043052-ef80f4de418c h1:8guNDWaL4d4Nsl+ptn2Z6ND/twrPtVYqy4+HxwSFPt8=
github.com/pingcap/parser v0.0.0-20200413043052-ef80f4de418c/go.mod h1:9v0Edh8IbgjGYW2ArJr19E+bvL8zKahsFp+ixWeId+4=
github.com/pingcap/pd/v4 v4.0.0-beta.1.0.20200305072537-61d9f9cc35d3 h1:Yrp99FnjHAEuDrSBql2l0IqCtJX7KwJbTsD5hIArkvk=
github.com/pingcap/pd/v4 v4.0.0-beta.1.0.20200305072537-61d9f9cc35d3/go.mod h1:25GfNw6+Jcr9kca5rtmTb4gKCJ4jOpow2zV2S9Dgafs=
github.com/pingcap/sysutil v0.0.0-20200206130906-2bfa6dc40bcd/go.mod h1:EB/852NMQ+aRKioCpToQ94Wl7fktV+FNnxf3CX/TTXI=

View File

@ -31,6 +31,7 @@ import (
"github.com/pingcap/tidb/privilege"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/types"
driver "github.com/pingcap/tidb/types/parser_driver"
@ -263,6 +264,12 @@ func (e *Execute) checkPreparedPriv(ctx context.Context, sctx sessionctx.Context
return err
}
func (e *Execute) setFoundInPlanCache(sctx sessionctx.Context, opt bool) error {
vars := sctx.GetSessionVars()
err := vars.SetSystemVar(variable.TiDBFoundInPlanCache, variable.BoolToIntStr(opt))
return err
}
func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt) error {
stmtCtx := sctx.GetSessionVars().StmtCtx
prepared := preparedStmt.PreparedAst
@ -282,6 +289,10 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
} else {
planCacheCounter.Inc()
}
err = e.setFoundInPlanCache(sctx, true)
if err != nil {
return err
}
e.names = names
e.Plan = plan
stmtCtx.PointExec = true
@ -307,12 +318,16 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
}
}
if planValid {
err := e.setFoundInPlanCache(sctx, true)
if err != nil {
return err
}
if metrics.ResettablePlanCacheCounterFortTest {
metrics.PlanCacheCounter.WithLabelValues("prepare").Inc()
} else {
planCacheCounter.Inc()
}
err := e.rebuildRange(cachedVal.Plan)
err = e.rebuildRange(cachedVal.Plan)
if err != nil {
return err
}
@ -336,10 +351,16 @@ func (e *Execute) getPhysicalPlan(ctx context.Context, sctx sessionctx.Context,
isRange := e.isRangePartition(p)
_, isTableDual := p.(*PhysicalTableDual)
if !isTableDual && prepared.UseCache && !isRange {
err = e.setFoundInPlanCache(sctx, true)
if err != nil {
return err
}
cached := NewPSTMTPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan)
preparedStmt.NormalizedPlan, preparedStmt.PlanDigest = NormalizePlan(p)
stmtCtx.SetPlanDigest(preparedStmt.NormalizedPlan, preparedStmt.PlanDigest)
sctx.PreparedPlanCache().Put(cacheKey, cached)
} else {
err = e.setFoundInPlanCache(sctx, false)
}
return err
}

View File

@ -676,6 +676,46 @@ func (s *testPlanSerialSuite) TestPlanCacheUnionScan(c *C) {
c.Check(cnt, Equals, float64(6))
}
func (s *testPlanSerialSuite) TestPlanCacheHitInfo(c *C) {
defer testleak.AfterTest(c)()
store, dom, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
tk := testkit.NewTestKit(c, store)
orgEnable := core.PreparedPlanCacheEnabled()
defer func() {
dom.Close()
store.Close()
core.SetPreparedPlanCache(orgEnable)
}()
core.SetPreparedPlanCache(true)
tk.Se, err = session.CreateSession4TestWithOpt(store, &session.Opt{
PreparedPlanCache: kvcache.NewSimpleLRUCache(100, 0.1, math.MaxUint64),
})
c.Assert(err, IsNil)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(id int)")
tk.MustExec("insert into t values (1),(2),(3),(4)")
tk.MustExec("prepare stmt from 'select * from t where id=?'")
tk.MustExec("prepare stmt2 from 'select /*+ ignore_plan_cache() */ * from t where id=?'")
tk.MustExec("set @doma = 1")
// Test if last_plan_from_cache is appropriately initialized.
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
tk.MustQuery("execute stmt using @doma").Check(testkit.Rows("1"))
// Test if last_plan_from_cache is updated after a plan cache hit.
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustQuery("execute stmt2 using @doma").Check(testkit.Rows("1"))
// Test if last_plan_from_cache is updated after a plan cache miss caused by a prepared statement.
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
// Test if last_plan_from_cache is updated after a plan cache miss caused by a usual statement.
tk.MustQuery("execute stmt using @doma").Check(testkit.Rows("1"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustQuery("select * from t where id=1").Check(testkit.Rows("1"))
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
}
func (s *testPrepareSuite) TestPrepareForGroupByMultiItems(c *C) {
defer testleak.AfterTest(c)()
store, dom, err := newStoreWithBootstrap()

View File

@ -594,6 +594,11 @@ type SessionVars struct {
// WindowingUseHighPrecision determines whether to compute window operations without loss of precision.
// see https://dev.mysql.com/doc/refman/8.0/en/window-function-optimization.html for more details.
WindowingUseHighPrecision bool
// FoundInPlanCache indicates whether this statement was found in plan cache.
FoundInPlanCache bool
// PrevFoundInPlanCache indicates whether the last statement was found in plan cache.
PrevFoundInPlanCache bool
}
// PreparedParams contains the parameters of the current prepared statement when executing it.
@ -679,6 +684,8 @@ func NewSessionVars() *SessionVars {
MetricSchemaRangeDuration: DefTiDBMetricSchemaRangeDuration,
SequenceState: NewSequenceState(),
WindowingUseHighPrecision: true,
PrevFoundInPlanCache: DefTiDBFoundInPlanCache,
FoundInPlanCache: DefTiDBFoundInPlanCache,
}
vars.KVVars = kv.NewVariables(&vars.Killed)
vars.Concurrency = Concurrency{
@ -1247,6 +1254,8 @@ func (s *SessionVars) SetSystemVar(name string, val string) error {
atomic.StoreUint64(&config.GetGlobalConfig().Log.QueryLogMaxLen, uint64(tidbOptInt64(val, logutil.DefaultQueryLogMaxLen)))
case TiDBCheckMb4ValueInUTF8:
config.GetGlobalConfig().CheckMb4ValueInUTF8 = TiDBOptOn(val)
case TiDBFoundInPlanCache:
s.FoundInPlanCache = TiDBOptOn(val)
case TiDBEnableCollectExecutionInfo:
config.GetGlobalConfig().EnableCollectExecutionInfo = TiDBOptOn(val)
}

View File

@ -718,6 +718,7 @@ var defaultSysVars = []*SysVar{
{ScopeSession, TiDBEnableSlowLog, BoolToIntStr(logutil.DefaultTiDBEnableSlowLog)},
{ScopeSession, TiDBQueryLogMaxLen, strconv.Itoa(logutil.DefaultQueryLogMaxLen)},
{ScopeSession, TiDBCheckMb4ValueInUTF8, BoolToIntStr(config.GetGlobalConfig().CheckMb4ValueInUTF8)},
{ScopeSession, TiDBFoundInPlanCache, BoolToIntStr(DefTiDBFoundInPlanCache)},
{ScopeSession, TiDBEnableCollectExecutionInfo, BoolToIntStr(logutil.DefaultTiDBEnableSlowLog)},
}

View File

@ -169,6 +169,9 @@ const (
// TiDBCheckMb4ValueInUTF8 is used to control whether to enable the check wrong utf8 value.
TiDBCheckMb4ValueInUTF8 = "tidb_check_mb4_value_in_utf8"
// TiDBFoundInPlanCache indicates whether the last statement was found in plan cache
TiDBFoundInPlanCache = "last_plan_from_cache"
)
// TiDB system variable names that both in session and global scope.
@ -484,6 +487,7 @@ const (
DefTiDBStoreLimit = 0
DefTiDBMetricSchemaStep = 60 // 60s
DefTiDBMetricSchemaRangeDuration = 60 // 60s
DefTiDBFoundInPlanCache = false
DefTidbEnableCollectExecutionInfo = false
)

View File

@ -152,6 +152,8 @@ func GetSessionOnlySysVars(s *SessionVars, key string) (string, bool, error) {
return BoolToIntStr(config.GetGlobalConfig().CheckMb4ValueInUTF8), true, nil
case TiDBCapturePlanBaseline:
return CapturePlanBaseline.GetVal(), true, nil
case TiDBFoundInPlanCache:
return BoolToIntStr(s.PrevFoundInPlanCache), true, nil
case TiDBEnableCollectExecutionInfo:
return BoolToIntStr(config.GetGlobalConfig().EnableCollectExecutionInfo), true, nil
}
@ -419,8 +421,8 @@ func ValidateSetSystemVar(vars *SessionVars, name string, value string) (string,
TiDBBatchDelete, TiDBBatchCommit, TiDBEnableCascadesPlanner, TiDBEnableWindowFunction, TiDBPProfSQLCPU,
TiDBLowResolutionTSO, TiDBEnableIndexMerge, TiDBEnableNoopFuncs,
TiDBCheckMb4ValueInUTF8, TiDBEnableSlowLog, TiDBRecordPlanInSlowLog,
TiDBScatterRegion, TiDBGeneralLog, TiDBConstraintCheckInPlace, TiDBEnableVectorizedExpression,
TiDBEnableCollectExecutionInfo:
TiDBScatterRegion, TiDBGeneralLog, TiDBConstraintCheckInPlace,
TiDBEnableVectorizedExpression, TiDBFoundInPlanCache, TiDBEnableCollectExecutionInfo:
fallthrough
case GeneralLog, AvoidTemporalUpgrade, BigTables, CheckProxyUsers, LogBin,
CoreFile, EndMakersInJSON, SQLLogBin, OfflineMode, PseudoSlaveMode, LowPriorityUpdates,

View File

@ -84,6 +84,7 @@ func (s *testVarsutilSuite) TestNewSessionVars(c *C) {
c.Assert(vars.AllowWriteRowID, Equals, DefOptWriteRowID)
c.Assert(vars.TiDBOptJoinReorderThreshold, Equals, DefTiDBOptJoinReorderThreshold)
c.Assert(vars.EnableFastAnalyze, Equals, DefTiDBUseFastAnalyze)
c.Assert(vars.FoundInPlanCache, Equals, DefTiDBFoundInPlanCache)
assertFieldsGreaterThanZero(c, reflect.ValueOf(vars.Concurrency))
assertFieldsGreaterThanZero(c, reflect.ValueOf(vars.MemQuota))
@ -434,6 +435,13 @@ func (s *testVarsutilSuite) TestVarsutil(c *C) {
c.Assert(val, Equals, "0")
err = SetSessionSystemVar(v, TiDBStmtSummaryMaxSQLLength, types.NewStringDatum("a"))
c.Assert(err, ErrorMatches, ".*Incorrect argument type to variable 'tidb_stmt_summary_max_sql_length'")
err = SetSessionSystemVar(v, TiDBFoundInPlanCache, types.NewStringDatum("1"))
c.Assert(err, IsNil)
val, err = GetSessionSystemVar(v, TiDBFoundInPlanCache)
c.Assert(err, IsNil)
c.Assert(val, Equals, "0")
c.Assert(v.systems[TiDBFoundInPlanCache], Equals, "1")
}
func (s *testVarsutilSuite) TestSetOverflowBehave(c *C) {