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

Conversation

XuHuaiyu
Copy link
Contributor

@XuHuaiyu XuHuaiyu commented Dec 4, 2017

fix #5126
PTAL @winkyao
Before this commit:
When run show variables, TiDB will autorun sql SELECT VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME="%s";
to fetch the value of every VARIABLE_NAME which
caused bad performance as #5126 described.

After commit:
We get all the data just once hence avoiding the time cost.

On my machine, for sql:

SHOW VARIABLES WHERE Variable_name ='language' OR Variable_name = 'net_write_timeout' OR Variable_name = 'interactive_timeout' OR Variable_name = 'wait_timeout' OR Variable_name = 'character_set_client' OR Variable_name = 'character_set_connection' OR Variable_name = 'character_set' OR Variable_name = 'character_set_server' OR Variable_name = 'tx_isolation' OR Variable_name = 'transaction_isolation' OR Variable_name = 'character_set_results' OR Variable_name = 'timezone' OR Variable_name = 'time_zone' OR Variable_name = 'system_time_zone' OR Variable_name = 'lower_case_table_names' OR Variable_name = 'max_allowed_packet' OR Variable_name = 'net_buffer_length' OR Variable_name = 'sql_mode' OR Variable_name = 'query_cache_type' OR Variable_name = 'query_cache_size' OR Variable_name = 'license' OR Variable_name = 'init_connect';

before: 0.59s
after:0.03s

@@ -599,6 +601,12 @@ func (b *planBuilder) buildShow(show *ast.ShowStmt) Plan {
for i, col := range p.schema.Columns {
col.Position = i
}
if show.Tp == ast.ShowVariables {
Copy link
Contributor

Choose a reason for hiding this comment

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

why not handle this in line 582?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This action should be after schema building.
So it is put after line601~604.

if b.err != nil {
return p
}
for i, cols := 0, ds.Schema().Columns; i < len(cols); i++ {
Copy link
Contributor

Choose a reason for hiding this comment

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

for _, cols := range ds.Schema().Columns

@shenli
Copy link
Member

shenli commented Dec 4, 2017

It is better to use a sql like SELECT VARIABLE_NAME, VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME="%s" or VARIABLE_NAME="%s" or ......;.
Using things in the executor package will cause problem for future work.

@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Dec 4, 2017

PTAL @shenli
This implementation cost 0.07s 0.03s on my machine when run

SHOW VARIABLES WHERE Variable_name ='language' OR Variable_name = 'net_write_timeout' OR Variable_name = 'interactive_timeout' OR Variable_name = 'wait_timeout' OR Variable_name = 'character_set_client' OR Variable_name = 'character_set_connection' OR Variable_name = 'character_set' OR Variable_name = 'character_set_server' OR Variable_name = 'tx_isolation' OR Variable_name = 'transaction_isolation' OR Variable_name = 'character_set_results' OR Variable_name = 'timezone' OR Variable_name = 'time_zone' OR Variable_name = 'system_time_zone' OR Variable_name = 'lower_case_table_names' OR Variable_name = 'max_allowed_packet' OR Variable_name = 'net_buffer_length' OR Variable_name = 'sql_mode' OR Variable_name = 'query_cache_type' OR Variable_name = 'query_cache_size' OR Variable_name = 'license' OR Variable_name = 'init_connect';

It's slower than the last implementation since the last one can push the selection down to datasource.

@shenli
Copy link
Member

shenli commented Dec 4, 2017

@XuHuaiyu You can add a hint for this query which could reduce the cost of optimizer.

@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Dec 4, 2017

PTAL @winkyao @coocood

session.go Outdated
if s.Value(context.Initing) != nil {
return nil, nil
}
sql := `SELECT VARIABLE_NAME, VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME in (`
Copy link
Member

Choose a reason for hiding this comment

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

It will be even faster if we remove the IN condition.

Copy link
Contributor

Choose a reason for hiding this comment

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

GetAllSysVars does not need in condition, select all is OK.

session.go Outdated
if s.Value(context.Initing) != nil {
return nil, nil
}
sql := `SELECT VARIABLE_NAME, VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME in (`
Copy link
Contributor

Choose a reason for hiding this comment

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

GetAllSysVars does not need in condition, select all is OK.

executor/show.go Outdated
@@ -87,7 +87,7 @@ func (e *ShowExec) Next(goCtx goctx.Context) (Row, error) {
return row, nil
}

func (e *ShowExec) fetchAll() error {
func (e *ShowExec) fetchAll(goCtx goctx.Context) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

goctx is useless?

@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Dec 4, 2017

PTAL @coocood @winkyao @mccxj

executor/show.go Outdated
}
if err != nil {
return errors.Trace(err)
}
if !ok {
value, ok = systemVars[v.Name]
Copy link
Member

Choose a reason for hiding this comment

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

This will do.

if !ok {
  value = v.Value
}

executor/show.go Outdated
if !ok {
value, ok = systemVars[v.Name]
if !ok {
sv, ok2 := variable.SysVars[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.

ok2 is always true, because v was fetched from SysVars.

executor/show.go Outdated
value, ok = systemVars[v.Name]
if !ok {
sv, ok2 := variable.SysVars[v.Name]
isUninitializedGlobalVariable := ok2 && sv.Scope|variable.ScopeGlobal > 0
Copy link
Contributor

Choose a reason for hiding this comment

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

as an early bug. "sv.Scope|variable.ScopeGlobal > 0" is always true.

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.

}
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.

@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Dec 5, 2017

PTAL @coocood @winkyao

executor/show.go Outdated
} 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.

@winkyao
Copy link
Contributor

winkyao commented Dec 5, 2017

reset LGTM

@coocood
Copy link
Member

coocood commented Dec 5, 2017

LGTM

@XuHuaiyu
Copy link
Contributor Author

XuHuaiyu commented Dec 5, 2017

PTAL @winkyao

@coocood coocood added the status/LGT1 Indicates that a PR has LGTM 1. label Dec 5, 2017
Copy link
Contributor

@winkyao winkyao left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@mccxj mccxj left a comment

Choose a reason for hiding this comment

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

LGTM

@XuHuaiyu XuHuaiyu added status/LGT2 Indicates that a PR has LGTM 2. and removed status/LGT1 Indicates that a PR has LGTM 1. labels Dec 5, 2017
@coocood coocood merged commit 714b68c into pingcap:master Dec 5, 2017
XuHuaiyu added a commit to XuHuaiyu/tidb that referenced this pull request Dec 11, 2017
coocood pushed a commit that referenced this pull request Dec 11, 2017
* show: fix variable scope error (#5291)

* *: improve performance of show variables (#5297)

* *: session variable value should not be modified when get global variable (#5317)

* fix ci

* ddl,expression: make leak test more stable (#4895)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/LGT2 Indicates that a PR has LGTM 2.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve show variables performance.
5 participants