Skip to content

Commit

Permalink
*: wrap the previous statement for performance (pingcap#12283)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackysp authored and sre-bot committed Sep 23, 2019
1 parent ea963cb commit 582076b
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 41 deletions.
26 changes: 15 additions & 11 deletions executor/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/pingcap/tidb/util/memory"
"github.com/pingcap/tidb/util/sqlexec"
"github.com/pingcap/tidb/util/stmtsummary"
"github.com/pingcap/tidb/util/stringutil"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
Expand Down Expand Up @@ -180,7 +181,8 @@ func (a *recordSet) Close() error {
err := a.executor.Close()
a.stmt.LogSlowQuery(a.txnStartTS, a.lastErr == nil)
sessVars := a.stmt.Ctx.GetSessionVars()
sessVars.PrevStmt = FormatSQL(a.stmt.OriginText(), sessVars)
pps := types.CloneRow(sessVars.PreparedParams)
sessVars.PrevStmt = FormatSQL(a.stmt.OriginText(), pps)
a.stmt.logAudit()
a.stmt.SummaryStmt()
return err
Expand Down Expand Up @@ -731,13 +733,15 @@ func (a *ExecStmt) logAudit() {
}

// FormatSQL is used to format the original SQL, e.g. truncating long SQL, appending prepared arguments.
func FormatSQL(sql string, sessVars *variable.SessionVars) string {
cfg := config.GetGlobalConfig()
length := len(sql)
if maxQueryLen := atomic.LoadUint64(&cfg.Log.QueryLogMaxLen); uint64(length) > maxQueryLen {
sql = fmt.Sprintf("%.*q(len:%d)", maxQueryLen, sql, length)
func FormatSQL(sql string, pps variable.PreparedParams) stringutil.StringerFunc {
return func() string {
cfg := config.GetGlobalConfig()
length := len(sql)
if maxQueryLen := atomic.LoadUint64(&cfg.Log.QueryLogMaxLen); uint64(length) > maxQueryLen {
sql = fmt.Sprintf("%.*q(len:%d)", maxQueryLen, sql, length)
}
return QueryReplacer.Replace(sql) + pps.String()
}
return QueryReplacer.Replace(sql) + sessVars.GetExecuteArgumentsInfo()
}

// LogSlowQuery is used to print the slow query in the log files.
Expand All @@ -753,7 +757,7 @@ func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) {
if costTime < threshold && level > zapcore.DebugLevel {
return
}
sql := FormatSQL(a.Text, sessVars)
sql := FormatSQL(a.Text, sessVars.PreparedParams)

var tableIDs, indexNames string
if len(sessVars.StmtCtx.TableIDs) > 0 {
Expand All @@ -769,7 +773,7 @@ func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) {
_, digest := sessVars.StmtCtx.SQLDigest()
slowItems := &variable.SlowQueryLogItems{
TxnTS: txnTS,
SQL: sql,
SQL: sql.String(),
Digest: digest,
TimeTotal: costTime,
TimeParse: a.Ctx.GetSessionVars().DurationParse,
Expand All @@ -782,7 +786,7 @@ func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) {
Succ: succ,
}
if _, ok := a.StmtNode.(*ast.CommitStmt); ok {
slowItems.PrevStmt = sessVars.PrevStmt
slowItems.PrevStmt = sessVars.PrevStmt.String()
}
if costTime < threshold {
logutil.SlowQueryLogger.Debug(sessVars.SlowLogFormat(slowItems))
Expand All @@ -796,7 +800,7 @@ func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) {
userString = sessVars.User.String()
}
domain.GetDomain(a.Ctx).LogSlowQuery(&domain.SlowQueryInfo{
SQL: sql,
SQL: sql.String(),
Digest: digest,
Start: a.Ctx.GetSessionVars().StartTime,
Duration: costTime,
Expand Down
2 changes: 1 addition & 1 deletion server/conn_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ func (cc *clientConn) handleSetOption(data []byte) (err error) {
func (cc *clientConn) preparedStmt2String(stmtID uint32) string {
sv := cc.ctx.GetSessionVars()
if prepared, ok := sv.PreparedStmts[stmtID]; ok {
return prepared.Stmt.Text() + sv.GetExecuteArgumentsInfo()
return prepared.Stmt.Text() + sv.PreparedParams.String()
}
return "prepared statement not found, ID: " + strconv.FormatUint(uint64(stmtID), 10)
}
4 changes: 2 additions & 2 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ func (s *session) retry(ctx context.Context, maxCnt uint) (err error) {
zap.Int64("schemaVersion", schemaVersion),
zap.Uint("retryCnt", retryCnt),
zap.Int("queryNum", i),
zap.String("sql", sqlForLog(st.OriginText())+sessVars.GetExecuteArgumentsInfo()))
zap.String("sql", sqlForLog(st.OriginText())+sessVars.PreparedParams.String()))
} else {
logutil.Logger(ctx).Warn("retrying",
zap.Int64("schemaVersion", schemaVersion),
Expand Down Expand Up @@ -1967,7 +1967,7 @@ func logQuery(query string, vars *variable.SessionVars) {
zap.Int64("schemaVersion", vars.TxnCtx.SchemaVersion),
zap.Uint64("txnStartTS", vars.TxnCtx.StartTS),
zap.String("current_db", vars.CurrentDB),
zap.String("sql", query+vars.GetExecuteArgumentsInfo()))
zap.String("sql", query+vars.PreparedParams.String()))
}
}

Expand Down
4 changes: 3 additions & 1 deletion session/tidb.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/logutil"
Expand Down Expand Up @@ -226,7 +227,8 @@ func runStmt(ctx context.Context, sctx sessionctx.Context, s sqlexec.Statement)
if rs == nil {
s.(*executor.ExecStmt).LogSlowQuery(origTxnCtx.StartTS, err == nil)
s.(*executor.ExecStmt).SummaryStmt()
sessVars.PrevStmt = executor.FormatSQL(s.OriginText(), sessVars)
pps := types.CloneRow(sessVars.PreparedParams)
sessVars.PrevStmt = executor.FormatSQL(s.OriginText(), pps)
}
}()

Expand Down
34 changes: 12 additions & 22 deletions sessionctx/variable/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ type SessionVars struct {
// preparedStmtID is id of prepared statement.
preparedStmtID uint32
// PreparedParams params for prepared statements
PreparedParams []types.Datum
PreparedParams PreparedParams

// ActiveRoles stores active roles for current user
ActiveRoles []*auth.RoleIdentity
Expand Down Expand Up @@ -407,7 +407,7 @@ type SessionVars struct {
DurationCompile time.Duration

// PrevStmt is used to store the previous executed statement in the current session.
PrevStmt string
PrevStmt fmt.Stringer

// AllowRemoveAutoInc indicates whether a user can drop the auto_increment column attribute or not.
AllowRemoveAutoInc bool
Expand All @@ -424,6 +424,16 @@ type SessionVars struct {
replicaRead kv.ReplicaReadType
}

// PreparedParams contains the parameters of the current prepared statement when executing it.
type PreparedParams []types.Datum

func (pps PreparedParams) String() string {
if len(pps) == 0 {
return ""
}
return " [arguments: " + types.DatumsToStrNoErr(pps) + "]"
}

// ConnectionInfo present connection used by audit.
type ConnectionInfo struct {
ConnectionID uint32
Expand Down Expand Up @@ -642,26 +652,6 @@ func (s *SessionVars) Location() *time.Location {
return loc
}

// GetExecuteArgumentsInfo gets the argument list as a string of execute statement.
func (s *SessionVars) GetExecuteArgumentsInfo() string {
if len(s.PreparedParams) == 0 {
return ""
}
args := make([]string, 0, len(s.PreparedParams))
for _, v := range s.PreparedParams {
if v.IsNull() {
args = append(args, "<nil>")
} else {
str, err := v.ToString()
if err != nil {
terror.Log(err)
}
args = append(args, str)
}
}
return fmt.Sprintf(" [arguments: %s]", strings.Join(args, ", "))
}

// GetSystemVar gets the string value of a system variable.
func (s *SessionVars) GetSystemVar(name string) (string, bool) {
val, ok := s.systems[name]
Expand Down
8 changes: 4 additions & 4 deletions util/stringutil/string_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,17 +252,17 @@ func Copy(src string) string {
return string(hack.Slice(src))
}

// stringerFunc defines string func implement fmt.Stringer.
type stringerFunc func() string
// StringerFunc defines string func implement fmt.Stringer.
type StringerFunc func() string

// String implements fmt.Stringer
func (l stringerFunc) String() string {
func (l StringerFunc) String() string {
return l()
}

// MemoizeStr returns memoized version of stringFunc.
func MemoizeStr(l func() string) fmt.Stringer {
return stringerFunc(func() string {
return StringerFunc(func() string {
return l()
})
}
Expand Down

0 comments on commit 582076b

Please sign in to comment.