planner: clean useless Plan Cache code of binary protocol parameters (#36887)

ref pingcap/tidb#36598
This commit is contained in:
Yuanjia Zhang
2022-08-04 16:58:06 +08:00
committed by GitHub
parent fff7483487
commit 5e00a1540f
3 changed files with 45 additions and 77 deletions

View File

@ -15,7 +15,6 @@
package core
import (
"bytes"
"math"
"strconv"
"time"
@ -206,21 +205,16 @@ type PlanCacheValue struct {
Plan Plan
OutPutNames []*types.FieldName
TblInfo2UnionScan map[*model.TableInfo]bool
TxtVarTypes FieldSlice // variable types under text protocol
BinVarTypes []byte // variable types under binary protocol
IsBinProto bool // whether this plan is under binary protocol
TxtVarTypes FieldSlice
}
func (v *PlanCacheValue) varTypesUnchanged(binVarTps []byte, txtVarTps []*types.FieldType) bool {
if v.IsBinProto {
return bytes.Equal(v.BinVarTypes, binVarTps)
}
func (v *PlanCacheValue) varTypesUnchanged(txtVarTps []*types.FieldType) bool {
return v.TxtVarTypes.CheckTypesCompatibility4PC(txtVarTps)
}
// NewPlanCacheValue creates a SQLCacheValue.
func NewPlanCacheValue(plan Plan, names []*types.FieldName, srcMap map[*model.TableInfo]bool,
isBinProto bool, binVarTypes []byte, txtVarTps []*types.FieldType) *PlanCacheValue {
txtVarTps []*types.FieldType) *PlanCacheValue {
dstMap := make(map[*model.TableInfo]bool)
for k, v := range srcMap {
dstMap[k] = v
@ -234,8 +228,6 @@ func NewPlanCacheValue(plan Plan, names []*types.FieldName, srcMap map[*model.Ta
OutPutNames: names,
TblInfo2UnionScan: dstMap,
TxtVarTypes: userVarTypes,
BinVarTypes: binVarTypes,
IsBinProto: isBinProto,
}
}

View File

@ -189,8 +189,7 @@ type Execute struct {
baseSchemaProducer
Name string
TxtProtoVars []expression.Expression // parsed variables under text protocol
BinProtoVars []types.Datum // parsed variables under binary protocol
TxtProtoVars []expression.Expression
ExecID uint32
Stmt ast.StmtNode
StmtType string
@ -229,41 +228,27 @@ func (e *Execute) OptimizePreparedPlan(ctx context.Context, sctx sessionctx.Cont
prepared := preparedObj.PreparedAst
vars.StmtCtx.StmtType = prepared.StmtType
paramLen := len(e.BinProtoVars)
if paramLen > 0 {
// for binary protocol execute, argument is placed in vars.BinProtoVars
if len(prepared.Params) != paramLen {
return errors.Trace(ErrWrongParamCount)
}
vars.PreparedParams = e.BinProtoVars
for i, val := range vars.PreparedParams {
param := prepared.Params[i].(*driver.ParamMarkerExpr)
param.Datum = val
param.InExecute = true
}
} else {
// for `execute stmt using @a, @b, @c`, using value in e.TxtProtoVars
if len(prepared.Params) != len(e.TxtProtoVars) {
return errors.Trace(ErrWrongParamCount)
}
// for `execute stmt using @a, @b, @c`, using value in e.TxtProtoVars
if len(prepared.Params) != len(e.TxtProtoVars) {
return errors.Trace(ErrWrongParamCount)
}
for i, usingVar := range e.TxtProtoVars {
val, err := usingVar.Eval(chunk.Row{})
if err != nil {
return err
}
param := prepared.Params[i].(*driver.ParamMarkerExpr)
if isGetVarBinaryLiteral(sctx, usingVar) {
binVal, convErr := val.ToBytes()
if convErr != nil {
return convErr
}
val.SetBinaryLiteral(binVal)
}
param.Datum = val
param.InExecute = true
vars.PreparedParams = append(vars.PreparedParams, val)
for i, usingVar := range e.TxtProtoVars {
val, err := usingVar.Eval(chunk.Row{})
if err != nil {
return err
}
param := prepared.Params[i].(*driver.ParamMarkerExpr)
if isGetVarBinaryLiteral(sctx, usingVar) {
binVal, convErr := val.ToBytes()
if convErr != nil {
return convErr
}
val.SetBinaryLiteral(binVal)
}
param.Datum = val
param.InExecute = true
vars.PreparedParams = append(vars.PreparedParams, val)
}
if prepared.SchemaVersion != is.SchemaMetaVersion() {
@ -297,7 +282,7 @@ func (e *Execute) OptimizePreparedPlan(ctx context.Context, sctx sessionctx.Cont
prepared.CachedPlan = nil
vars.LastUpdateTime4PC = expiredTimeStamp4PC
}
plan, names, err := GetPlanFromSessionPlanCache(ctx, sctx, is, preparedObj, e.BinProtoVars, e.TxtProtoVars)
plan, names, err := GetPlanFromSessionPlanCache(ctx, sctx, is, preparedObj, e.TxtProtoVars)
if err != nil {
return err
}

View File

@ -44,7 +44,7 @@ import (
// It tries to get a valid cached plan from this session's plan cache.
// If there is no such a plan, it'll call the optimizer to generate a new one.
func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt,
binProtoVars []types.Datum, txtProtoVars []expression.Expression) (plan Plan, names []*types.FieldName, err error) {
txtProtoVars []expression.Expression) (plan Plan, names []*types.FieldName, err error) {
var cacheKey kvcache.Key
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx
@ -72,8 +72,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i
}
}
isBinProtocol := len(binProtoVars) > 0
varsNum, binVarTypes, txtVarTypes := parseParamTypes(sctx, isBinProtocol, binProtoVars, txtProtoVars)
varsNum, txtVarTypes := parseParamTypes(sctx, txtProtoVars)
if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // for point query plan
if plan, names, ok, err := getPointQueryPlan(prepared, sessVars, stmtCtx); ok {
@ -83,39 +82,31 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i
if prepared.UseCache && !ignorePlanCache { // for general plans
if plan, names, ok, err := getGeneralPlan(ctx, sctx, cacheKey, bindSQL, is, preparedStmt,
binVarTypes, txtVarTypes); err != nil || ok {
txtVarTypes); err != nil || ok {
return plan, names, err
}
}
return generateNewPlan(ctx, sctx, is, preparedStmt, ignorePlanCache, cacheKey,
latestSchemaVersion, isBinProtocol, varsNum, binVarTypes, txtVarTypes, bindSQL)
latestSchemaVersion, varsNum, txtVarTypes, bindSQL)
}
// parseParamTypes get parameters' types in PREPARE statement
func parseParamTypes(sctx sessionctx.Context, isBinProtocol bool, binProtoVars []types.Datum,
txtProtoVars []expression.Expression) (varsNum int, binVarTypes []byte, txtVarTypes []*types.FieldType) {
if isBinProtocol { // binary protocol
varsNum = len(binProtoVars)
for _, param := range binProtoVars {
binVarTypes = append(binVarTypes, param.Kind())
func parseParamTypes(sctx sessionctx.Context, txtProtoVars []expression.Expression) (varsNum int, txtVarTypes []*types.FieldType) {
varsNum = len(txtProtoVars)
for _, param := range txtProtoVars {
if c, ok := param.(*expression.Constant); ok { // from binary protocol
txtVarTypes = append(txtVarTypes, c.GetType())
continue
}
} else { // txt protocol
varsNum = len(txtProtoVars)
for _, param := range txtProtoVars {
if c, ok := param.(*expression.Constant); ok { // from binary protocol
txtVarTypes = append(txtVarTypes, c.GetType())
continue
}
// from text protocol, there must be a GetVar function
name := param.(*expression.ScalarFunction).GetArgs()[0].String()
tp := sctx.GetSessionVars().UserVarTypes[name]
if tp == nil {
tp = types.NewFieldType(mysql.TypeNull)
}
txtVarTypes = append(txtVarTypes, tp)
// from text protocol, there must be a GetVar function
name := param.(*expression.ScalarFunction).GetArgs()[0].String()
tp := sctx.GetSessionVars().UserVarTypes[name]
if tp == nil {
tp = types.NewFieldType(mysql.TypeNull)
}
txtVarTypes = append(txtVarTypes, tp)
}
return
}
@ -145,7 +136,7 @@ func getPointQueryPlan(prepared *ast.Prepared, sessVars *variable.SessionVars, s
}
func getGeneralPlan(ctx context.Context, sctx sessionctx.Context, cacheKey kvcache.Key, bindSQL string,
is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt, binVarTypes []byte, txtVarTypes []*types.FieldType) (Plan,
is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt, txtVarTypes []*types.FieldType) (Plan,
[]*types.FieldName, bool, error) {
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx
@ -156,7 +147,7 @@ func getGeneralPlan(ctx context.Context, sctx sessionctx.Context, cacheKey kvcac
}
cachedVals := cacheValue.([]*PlanCacheValue)
for _, cachedVal := range cachedVals {
if !cachedVal.varTypesUnchanged(binVarTypes, txtVarTypes) {
if !cachedVal.varTypesUnchanged(txtVarTypes) {
continue
}
planValid := true
@ -198,7 +189,7 @@ func getGeneralPlan(ctx context.Context, sctx sessionctx.Context, cacheKey kvcac
// generateNewPlan call the optimizer to generate a new plan for current statement
// and try to add it to cache
func generateNewPlan(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt,
ignorePlanCache bool, cacheKey kvcache.Key, latestSchemaVersion int64, isBinProtocol bool, varsNum int, binVarTypes []byte,
ignorePlanCache bool, cacheKey kvcache.Key, latestSchemaVersion int64, varsNum int,
txtVarTypes []*types.FieldType, bindSQL string) (Plan, []*types.FieldName, error) {
prepared := preparedStmt.PreparedAst
sessVars := sctx.GetSessionVars()
@ -229,14 +220,14 @@ func generateNewPlan(ctx context.Context, sctx sessionctx.Context, is infoschema
}
sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{}
}
cached := NewPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan, isBinProtocol, binVarTypes, txtVarTypes)
cached := NewPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan, txtVarTypes)
preparedStmt.NormalizedPlan, preparedStmt.PlanDigest = NormalizePlan(p)
stmtCtx.SetPlan(p)
stmtCtx.SetPlanDigest(preparedStmt.NormalizedPlan, preparedStmt.PlanDigest)
if cacheVals, exists := sctx.PreparedPlanCache().Get(cacheKey); exists {
hitVal := false
for i, cacheVal := range cacheVals.([]*PlanCacheValue) {
if cacheVal.varTypesUnchanged(binVarTypes, txtVarTypes) {
if cacheVal.varTypesUnchanged(txtVarTypes) {
hitVal = true
cacheVals.([]*PlanCacheValue)[i] = cached
break