Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: improve performance of show variables #5297

Merged
merged 16 commits into from
Dec 5, 2017
Merged
2 changes: 1 addition & 1 deletion context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (t basicCtxType) String() string {
const (
// QueryString is the key for original query string.
QueryString basicCtxType = 1
// Initing is the key for indicating if the server is running bootstrap or upgrad job.
// Initing is the key for indicating if the server is running bootstrap or upgrade job.
Initing basicCtxType = 2
// LastExecuteDDL is the key for whether the session execute a ddl command last time.
LastExecuteDDL basicCtxType = 3
Expand Down
21 changes: 16 additions & 5 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,18 +372,29 @@ func (e *ShowExec) fetchShowCharset() error {

func (e *ShowExec) fetchShowVariables() error {
sessionVars := e.ctx.GetSessionVars()
systemVars, err := sessionVars.GlobalVarsAccessor.GetAllSysVars()
if err != nil {
return errors.Trace(err)
}
var (
value string
ok bool
)
for _, v := range variable.SysVars {
var err error
var value string
if !e.GlobalScope {
// Try to get Session Scope variable value first.
value, err = varsutil.GetSessionSystemVar(sessionVars, v.Name)
value, ok, err = varsutil.GetSessionOnlySysVars(sessionVars, v.Name)
} else {
value, err = varsutil.GetGlobalSystemVar(sessionVars, v.Name)
value, ok, err = varsutil.GetScopeNoneSystemVar(v.Name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add some comment here. about session scope, global scope and none scope, it is confused.

if terror.ErrorEqual(err, variable.ErrIncorrectScope) {
continue
}
}
if err != nil {
return errors.Trace(err)
}
if !ok {
value = systemVars[v.Name]
}
row := types.MakeDatums(v.Name, value)
e.rows = append(e.rows, row)
}
Expand Down
18 changes: 18 additions & 0 deletions session.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,24 @@ func (s *session) getExecRet(ctx context.Context, sql string) (string, error) {
return value, nil
}

// GetAllSysVars implements GlobalVarAccessor.GetAllSysVars interface.
func (s *session) GetAllSysVars() (map[string]string, error) {
if s.Value(context.Initing) != nil {
return nil, nil
}
sql := `SELECT VARIABLE_NAME, VARIABLE_VALUE FROM %s.%s;`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we load all global variables from tikv?

Copy link
Contributor Author

@XuHuaiyu XuHuaiyu Dec 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes no difference for performance,
since SysVars hold almost all the variable names(https://github.com/pingcap/tidb/blob/master/sessionctx/variable/sysvar.go#L99).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I care about the performance, not the memory consuming. We only need to load the variables that in the show variable statement.

sql = fmt.Sprintf(sql, mysql.SystemDB, mysql.GlobalVariablesTable)
rows, _, err := s.ExecRestrictedSQL(s, sql)
if err != nil {
return nil, errors.Trace(err)
}
ret := make(map[string]string)
for _, r := range rows {
ret[r.GetString(0)] = ret[r.GetString(1)]
}
return ret, nil
}

// GetGlobalSysVar implements GlobalVarAccessor.GetGlobalSysVar interface.
func (s *session) GetGlobalSysVar(name string) (string, error) {
if s.Value(context.Initing) != nil {
Expand Down
2 changes: 2 additions & 0 deletions sessionctx/variable/sysvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ const (

// GlobalVarAccessor is the interface for accessing global scope system and status variables.
type GlobalVarAccessor interface {
// GetAllSysVars gets all the global system variable values.
GetAllSysVars() (map[string]string, error)
// GetGlobalSysVar gets the global system variable value for name.
GetGlobalSysVar(name string) (string, error)
// SetGlobalSysVar sets the global system variable name to value.
Expand Down
53 changes: 37 additions & 16 deletions sessionctx/varsutil/varsutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,48 +30,69 @@ import (
// Returns error if there is no such variable.
func GetSessionSystemVar(s *variable.SessionVars, key string) (string, error) {
key = strings.ToLower(key)
gVal, ok, err := GetSessionOnlySysVars(s, key)
if err != nil || ok {
return gVal, errors.Trace(err)
}
gVal, err = s.GlobalVarsAccessor.GetGlobalSysVar(key)
if err != nil {
return "", errors.Trace(err)
}
s.Systems[key] = gVal
return gVal, nil
}

// GetSessionOnlySysVars get the default value defined in code for session only variable.
// The return bool value indicates whether it's a session only variable.
func GetSessionOnlySysVars(s *variable.SessionVars, key string) (string, bool, error) {
sysVar := variable.SysVars[key]
if sysVar == nil {
return "", variable.UnknownSystemVar.GenByArgs(key)
return "", false, variable.UnknownSystemVar.GenByArgs(key)
}
// For virtual system variables:
switch sysVar.Name {
case variable.TiDBCurrentTS:
return fmt.Sprintf("%d", s.TxnCtx.StartTS), nil
return fmt.Sprintf("%d", s.TxnCtx.StartTS), true, nil
}
sVal, ok := s.Systems[key]
if ok {
return sVal, nil
return sVal, true, nil
}
if sysVar.Scope&variable.ScopeGlobal == 0 {
// None-Global variable can use pre-defined default value.
return sysVar.Value, nil
return sysVar.Value, true, nil
}
gVal, err := s.GlobalVarsAccessor.GetGlobalSysVar(key)
return "", false, nil
}

// GetGlobalSystemVar gets a global system variable.
func GetGlobalSystemVar(s *variable.SessionVars, key string) (string, error) {
key = strings.ToLower(key)
gVal, ok, err := GetScopeNoneSystemVar(key)
if err != nil || ok {
return gVal, errors.Trace(err)
}
gVal, err = s.GlobalVarsAccessor.GetGlobalSysVar(key)
if err != nil {
return "", errors.Trace(err)
}
s.Systems[key] = gVal
return gVal, nil
}

// GetGlobalSystemVar gets a global system variable.
func GetGlobalSystemVar(s *variable.SessionVars, key string) (string, error) {
key = strings.ToLower(key)
// GetScopeNoneSystemVar checks the validation of `key`,
// and return the default value if its scope is `ScopeNone`.
func GetScopeNoneSystemVar(key string) (string, bool, error) {
sysVar := variable.SysVars[key]
if sysVar == nil {
return "", variable.UnknownSystemVar.GenByArgs(key)
return "", false, variable.UnknownSystemVar.GenByArgs(key)
}
if sysVar.Scope == variable.ScopeSession {
return "", variable.ErrIncorrectScope
return "", false, variable.ErrIncorrectScope
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move this error to GetGlobalSystemVar.

} else if sysVar.Scope == variable.ScopeNone {
return sysVar.Value, nil
return sysVar.Value, true, nil
}
gVal, err := s.GlobalVarsAccessor.GetGlobalSysVar(key)
if err != nil {
return "", errors.Trace(err)
}
return gVal, nil
return "", false, nil
}

// epochShiftBits is used to reserve logical part of the timestamp.
Expand Down
4 changes: 4 additions & 0 deletions sessionctx/varsutil/varsutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,7 @@ func (m *mockGlobalAccessor) SetGlobalSysVar(name string, value string) error {
m.vars[name] = value
return nil
}

func (m *mockGlobalAccessor) GetAllSysVars() (map[string]string, error) {
return m.vars, nil
}