planner, sessionctx : Add 'last_plan_from_cache' to help know whether sql's plan is from plan cache (#16321)
This commit is contained in:
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
2
go.mod
@ -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
4
go.sum
@ -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=
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)},
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
)
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user