Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Xiaomi
soar
提交
d9f6ef72
S
soar
项目概览
Xiaomi
/
soar
大约 1 年 前同步成功
通知
387
Star
8512
Fork
1328
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
soar
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d9f6ef72
编写于
12月 28, 2018
作者:
martianzhang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
for test coverage
上级
407db8a0
变更
10
展开全部
隐藏空白更改
内联
并排
Showing
10 changed file
with
300 addition
and
14 deletion
+300
-14
advisor/explainer_test.go
advisor/explainer_test.go
+7
-1
advisor/testdata/TestDigestExplainText.golden
advisor/testdata/TestDigestExplainText.golden
+109
-0
ast/rewrite.go
ast/rewrite.go
+2
-2
ast/rewrite_test.go
ast/rewrite_test.go
+16
-0
ast/testdata/TestListRewriteRules.golden
ast/testdata/TestListRewriteRules.golden
+140
-0
database/explain.go
database/explain.go
+10
-5
database/explain_test.go
database/explain_test.go
+8
-6
database/mysql.go
database/mysql.go
+1
-0
database/profiling_test.go
database/profiling_test.go
+4
-0
database/testdata/TestMySQLExplainQueryCost.golden
database/testdata/TestMySQLExplainQueryCost.golden
+3
-0
未找到文件。
advisor/explainer_test.go
浏览文件 @
d9f6ef72
...
@@ -31,7 +31,13 @@ func TestDigestExplainText(t *testing.T) {
...
@@ -31,7 +31,13 @@ func TestDigestExplainText(t *testing.T) {
| 1 | SIMPLE | city | ref | idx_fk_country_id,idx_country_id_city,idx_all,idx_other | idx_fk_country_id | 2 | sakila.country.country_id | 2 | Using index |
| 1 | SIMPLE | city | ref | idx_fk_country_id,idx_country_id_city,idx_all,idx_other | idx_fk_country_id | 2 | sakila.country.country_id | 2 | Using index |
+----+-------------+---------+-------+---------------------------------------------------------+-------------------+---------+---------------------------+------+-------------+`
+----+-------------+---------+-------+---------------------------------------------------------+-------------------+---------+---------------------------+------+-------------+`
common
.
Config
.
ReportType
=
"explain-digest"
common
.
Config
.
ReportType
=
"explain-digest"
err
:=
common
.
GoldenDiff
(
func
()
{
DigestExplainText
(
text
)
},
t
.
Name
(),
update
)
err
:=
common
.
GoldenDiff
(
func
()
{
DigestExplainText
(
text
)
orgReportType
:=
common
.
Config
.
ReportType
common
.
Config
.
ReportType
=
"html"
DigestExplainText
(
text
)
common
.
Config
.
ReportType
=
orgReportType
},
t
.
Name
(),
update
)
if
nil
!=
err
{
if
nil
!=
err
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
...
...
advisor/testdata/TestDigestExplainText.golden
浏览文件 @
d9f6ef72
此差异已折叠。
点击以展开。
ast/rewrite.go
浏览文件 @
d9f6ef72
...
@@ -312,7 +312,7 @@ func (rw *Rewrite) RewriteStandard() *Rewrite {
...
@@ -312,7 +312,7 @@ func (rw *Rewrite) RewriteStandard() *Rewrite {
return
rw
return
rw
}
}
// RewriteAlwaysTrue alwaystrue: 删除恒真条件
// RewriteAlwaysTrue always
true: 删除恒真条件
func
(
rw
*
Rewrite
)
RewriteAlwaysTrue
()
(
reWriter
*
Rewrite
)
{
func
(
rw
*
Rewrite
)
RewriteAlwaysTrue
()
(
reWriter
*
Rewrite
)
{
array
:=
NewNodeList
(
rw
.
Stmt
)
array
:=
NewNodeList
(
rw
.
Stmt
)
tNode
:=
array
.
Head
tNode
:=
array
.
Head
...
@@ -340,7 +340,7 @@ func isAlwaysTrue(expr *sqlparser.ComparisonExpr) bool {
...
@@ -340,7 +340,7 @@ func isAlwaysTrue(expr *sqlparser.ComparisonExpr) bool {
expr
.
Operator
=
"!="
expr
.
Operator
=
"!="
case
"<=>"
:
case
"<=>"
:
expr
.
Operator
=
"="
expr
.
Operator
=
"="
case
">="
,
"<="
,
"!="
,
"="
:
case
">="
,
"<="
,
"!="
,
"="
,
">"
,
"<"
:
default
:
default
:
return
false
return
false
}
}
...
...
ast/rewrite_test.go
浏览文件 @
d9f6ef72
...
@@ -433,10 +433,18 @@ func TestRewriteAlwaysTrue(t *testing.T) {
...
@@ -433,10 +433,18 @@ func TestRewriteAlwaysTrue(t *testing.T) {
"input"
:
"SELECT count(col) FROM tbl where 1>=1;"
,
"input"
:
"SELECT count(col) FROM tbl where 1>=1;"
,
"output"
:
"select count(col) from tbl"
,
"output"
:
"select count(col) from tbl"
,
},
},
{
"input"
:
"SELECT count(col) FROM tbl where 2>1;"
,
"output"
:
"select count(col) from tbl"
,
},
{
{
"input"
:
"SELECT count(col) FROM tbl where 1<=1;"
,
"input"
:
"SELECT count(col) FROM tbl where 1<=1;"
,
"output"
:
"select count(col) from tbl"
,
"output"
:
"select count(col) from tbl"
,
},
},
{
"input"
:
"SELECT count(col) FROM tbl where 1<2;"
,
"output"
:
"select count(col) from tbl"
,
},
{
{
"input"
:
"SELECT count(col) FROM tbl where 1=1 and 2=2;"
,
"input"
:
"SELECT count(col) FROM tbl where 1=1 and 2=2;"
,
"output"
:
"select count(col) from tbl"
,
"output"
:
"select count(col) from tbl"
,
...
@@ -461,6 +469,10 @@ func TestRewriteAlwaysTrue(t *testing.T) {
...
@@ -461,6 +469,10 @@ func TestRewriteAlwaysTrue(t *testing.T) {
"input"
:
"SELECT count(col) FROM tbl where (1=1);"
,
"input"
:
"SELECT count(col) FROM tbl where (1=1);"
,
"output"
:
"select count(col) from tbl"
,
"output"
:
"select count(col) from tbl"
,
},
},
{
"input"
:
"SELECT count(col) FROM tbl where a=1;"
,
"output"
:
"select count(col) from tbl where a = 1"
,
},
{
{
"input"
:
"SELECT count(col) FROM tbl where ('a'= 'a' or 'b' = 'b') and a = 'b';"
,
"input"
:
"SELECT count(col) FROM tbl where ('a'= 'a' or 'b' = 'b') and a = 'b';"
,
"output"
:
"select count(col) from tbl where a = 'b'"
,
"output"
:
"select count(col) from tbl where a = 'b'"
,
...
@@ -777,6 +789,10 @@ func TestListRewriteRules(t *testing.T) {
...
@@ -777,6 +789,10 @@ func TestListRewriteRules(t *testing.T) {
common
.
Log
.
Debug
(
"Entering function: %s"
,
common
.
GetFunctionName
())
common
.
Log
.
Debug
(
"Entering function: %s"
,
common
.
GetFunctionName
())
err
:=
common
.
GoldenDiff
(
func
()
{
err
:=
common
.
GoldenDiff
(
func
()
{
ListRewriteRules
(
RewriteRules
)
ListRewriteRules
(
RewriteRules
)
orgReportType
:=
common
.
Config
.
ReportType
common
.
Config
.
ReportType
=
"json"
ListRewriteRules
(
RewriteRules
)
common
.
Config
.
ReportType
=
orgReportType
},
t
.
Name
(),
update
)
},
t
.
Name
(),
update
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
Error
(
err
)
...
...
ast/testdata/TestListRewriteRules.golden
浏览文件 @
d9f6ef72
...
@@ -270,3 +270,143 @@ use sakila
...
@@ -270,3 +270,143 @@ use sakila
```sql
```sql
use sakila;
use sakila;
```
```
[
{
"Name": "dml2select",
"Description": "将数据库更新请求转换为只读查询请求,便于执行EXPLAIN",
"Original": "DELETE FROM film WHERE length \u003e 100",
"Suggest": "select * from film where length \u003e 100"
},
{
"Name": "star2columns",
"Description": "为SELECT *补全表的列信息",
"Original": "SELECT * FROM film",
"Suggest": "select film.film_id, film.title from film"
},
{
"Name": "insertcolumns",
"Description": "为INSERT补全表的列信息",
"Original": "insert into film values(1,2,3,4,5)",
"Suggest": "insert into film(film_id, title, description, release_year, language_id) values (1, 2, 3, 4, 5)"
},
{
"Name": "having",
"Description": "将查询的 HAVING 子句改写为 WHERE 中的查询条件",
"Original": "SELECT state, COUNT(*) FROM Drivers GROUP BY state HAVING state IN ('GA', 'TX') ORDER BY state",
"Suggest": "select state, COUNT(*) from Drivers where state in ('GA', 'TX') group by state order by state asc"
},
{
"Name": "orderbynull",
"Description": "如果 GROUP BY 语句不指定 ORDER BY 条件会导致无谓的排序产生,如果不需要排序建议添加 ORDER BY NULL",
"Original": "SELECT sum(col1) FROM tbl GROUP BY col",
"Suggest": "select sum(col1) from tbl group by col order by null"
},
{
"Name": "unionall",
"Description": "可以接受重复的时间,使用 UNION ALL 替代 UNION 以提高查询效率",
"Original": "select country_id from city union select country_id from country",
"Suggest": "select country_id from city union all select country_id from country"
},
{
"Name": "or2in",
"Description": "将同一列不同条件的 OR 查询转写为 IN 查询",
"Original": "select country_id from city where col1 = 1 or (col2 = 1 or col2 = 2 ) or col1 = 3;",
"Suggest": "select country_id from city where (col2 in (1, 2)) or col1 in (1, 3);"
},
{
"Name": "innull",
"Description": "如果 IN 条件中可能有 NULL 值而又想匹配 NULL 值时,建议添加OR col IS NULL",
"Original": "暂不支持",
"Suggest": "暂不支持"
},
{
"Name": "or2union",
"Description": "将不同列的 OR 查询转为 UNION 查询,建议结合 unionall 重写策略一起使用",
"Original": "暂不支持",
"Suggest": "暂不支持"
},
{
"Name": "dmlorderby",
"Description": "删除 DML 更新操作中无意义的 ORDER BY",
"Original": "DELETE FROM tbl WHERE col1=1 ORDER BY col",
"Suggest": "delete from tbl where col1 = 1"
},
{
"Name": "sub2join",
"Description": "将子查询转换为JOIN查询",
"Original": "暂不支持",
"Suggest": "暂不支持"
},
{
"Name": "join2sub",
"Description": "将JOIN查询转换为子查询",
"Original": "暂不支持",
"Suggest": "暂不支持"
},
{
"Name": "distinctstar",
"Description": "DISTINCT *对有主键的表没有意义,可以将DISTINCT删掉",
"Original": "SELECT DISTINCT * FROM film;",
"Suggest": "SELECT * FROM film"
},
{
"Name": "standard",
"Description": "SQL标准化,如:关键字转换为小写",
"Original": "SELECT sum(col1) FROM tbl GROUP BY 1;",
"Suggest": "select sum(col1) from tbl group by 1"
},
{
"Name": "mergealter",
"Description": "合并同一张表的多条ALTER语句",
"Original": "ALTER TABLE t2 DROP COLUMN c;ALTER TABLE t2 DROP COLUMN d;",
"Suggest": "ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;"
},
{
"Name": "alwaystrue",
"Description": "删除无用的恒真判断条件",
"Original": "SELECT count(col) FROM tbl where 'a'= 'a' or ('b' = 'b' and a = 'b');",
"Suggest": "select count(col) from tbl where (a = 'b');"
},
{
"Name": "countstar",
"Description": "不建议使用COUNT(col)或COUNT(常量),建议改写为COUNT(*)",
"Original": "SELECT count(col) FROM tbl GROUP BY 1;",
"Suggest": "SELECT count(*) FROM tbl GROUP BY 1;"
},
{
"Name": "innodb",
"Description": "建表时建议使用InnoDB引擎,非 InnoDB 引擎表自动转 InnoDB",
"Original": "CREATE TABLE t1(id bigint(20) NOT NULL AUTO_INCREMENT);",
"Suggest": "create table t1 (\n\tid bigint(20) not null auto_increment\n) ENGINE=InnoDB;"
},
{
"Name": "autoincrement",
"Description": "将autoincrement初始化为1",
"Original": "CREATE TABLE t1(id bigint(20) NOT NULL AUTO_INCREMENT) ENGINE=InnoDB AUTO_INCREMENT=123802;",
"Suggest": "create table t1(id bigint(20) not null auto_increment) ENGINE=InnoDB auto_increment=1;"
},
{
"Name": "intwidth",
"Description": "整型数据类型修改默认显示宽度",
"Original": "create table t1 (id int(20) not null auto_increment) ENGINE=InnoDB;",
"Suggest": "create table t1 (id int(10) not null auto_increment) ENGINE=InnoDB;"
},
{
"Name": "truncate",
"Description": "不带 WHERE 条件的 DELETE 操作建议修改为 TRUNCATE",
"Original": "DELETE FROM tbl",
"Suggest": "truncate table tbl"
},
{
"Name": "rmparenthesis",
"Description": "去除没有意义的括号",
"Original": "select col from table where (col = 1);",
"Suggest": "select col from table where col = 1;"
},
{
"Name": "delimiter",
"Description": "补全DELIMITER",
"Original": "use sakila",
"Suggest": "use sakila;"
}
]
database/explain.go
浏览文件 @
d9f6ef72
...
@@ -604,6 +604,9 @@ func MySQLExplainWarnings(exp *ExplainInfo) string {
...
@@ -604,6 +604,9 @@ func MySQLExplainWarnings(exp *ExplainInfo) string {
// MySQLExplainQueryCost 将last_query_cost信息补充到评审结果中
// MySQLExplainQueryCost 将last_query_cost信息补充到评审结果中
func
MySQLExplainQueryCost
(
exp
*
ExplainInfo
)
string
{
func
MySQLExplainQueryCost
(
exp
*
ExplainInfo
)
string
{
var
content
string
var
content
string
if
exp
==
nil
{
return
content
}
if
exp
.
QueryCost
>
0
{
if
exp
.
QueryCost
>
0
{
tmp
:=
fmt
.
Sprintf
(
"%.3f
\n
"
,
exp
.
QueryCost
)
tmp
:=
fmt
.
Sprintf
(
"%.3f
\n
"
,
exp
.
QueryCost
)
...
@@ -819,7 +822,7 @@ func parseTraditionalExplainText(content string) (explainRows []*ExplainRow, err
...
@@ -819,7 +822,7 @@ func parseTraditionalExplainText(content string) (explainRows []*ExplainRow, err
}
}
// filtered may larger than 100.00
// filtered may larger than 100.00
// https://bugs.mysql.com/bug.php?id=34124
// https://bugs.mysql.com/bug.php?id=34124
if
filtered
>
100.00
{
if
filtered
>
=
100.00
{
filtered
=
100.00
filtered
=
100.00
}
}
...
@@ -1039,6 +1042,7 @@ func ParseExplainResult(res QueryResult, formatType int) (exp *ExplainInfo, err
...
@@ -1039,6 +1042,7 @@ func ParseExplainResult(res QueryResult, formatType int) (exp *ExplainInfo, err
// Explain 获取 SQL 的 explain 信息
// Explain 获取 SQL 的 explain 信息
func
(
db
*
Connector
)
Explain
(
sql
string
,
explainType
int
,
formatType
int
)
(
exp
*
ExplainInfo
,
err
error
)
{
func
(
db
*
Connector
)
Explain
(
sql
string
,
explainType
int
,
formatType
int
)
(
exp
*
ExplainInfo
,
err
error
)
{
exp
=
&
ExplainInfo
{
SQL
:
sql
}
if
explainType
!=
TraditionalExplainType
{
if
explainType
!=
TraditionalExplainType
{
formatType
=
TraditionalFormatExplain
formatType
=
TraditionalFormatExplain
}
}
...
@@ -1054,13 +1058,14 @@ func (db *Connector) Explain(sql string, explainType int, formatType int) (exp *
...
@@ -1054,13 +1058,14 @@ func (db *Connector) Explain(sql string, explainType int, formatType int) (exp *
}()
}()
// 执行EXPLAIN请求
// 执行EXPLAIN请求
sql
=
db
.
explainQuery
(
sql
,
explainType
,
formatType
)
exp
.
SQL
=
db
.
explainQuery
(
sql
,
explainType
,
formatType
)
res
,
err
:=
db
.
Query
(
sql
)
res
,
err
:=
db
.
Query
(
exp
.
SQL
)
if
err
!=
nil
{
return
exp
,
err
}
// 解析mysql结果,输出ExplainInfo
// 解析mysql结果,输出ExplainInfo
exp
,
err
=
ParseExplainResult
(
res
,
formatType
)
exp
,
err
=
ParseExplainResult
(
res
,
formatType
)
exp
.
SQL
=
sql
return
exp
,
err
return
exp
,
err
}
}
...
...
database/explain_test.go
浏览文件 @
d9f6ef72
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
package
database
package
database
import
(
import
(
"fmt"
"testing"
"testing"
"github.com/XiaoMi/soar/common"
"github.com/XiaoMi/soar/common"
...
@@ -2439,12 +2440,13 @@ func TestMySQLExplainWarnings(t *testing.T) {
...
@@ -2439,12 +2440,13 @@ func TestMySQLExplainWarnings(t *testing.T) {
func
TestMySQLExplainQueryCost
(
t
*
testing
.
T
)
{
func
TestMySQLExplainQueryCost
(
t
*
testing
.
T
)
{
common
.
Log
.
Debug
(
"Entering function: %s"
,
common
.
GetFunctionName
())
common
.
Log
.
Debug
(
"Entering function: %s"
,
common
.
GetFunctionName
())
expInfo
,
err
:=
connTest
.
Explain
(
"select 1"
,
TraditionalExplainType
,
TraditionalFormatExplain
)
err
:=
common
.
GoldenDiff
(
func
()
{
if
err
!=
nil
{
expInfo
,
err
:=
connTest
.
Explain
(
"select 1"
,
TraditionalExplainType
,
TraditionalFormatExplain
)
t
.
Error
(
err
)
fmt
.
Println
(
err
,
MySQLExplainQueryCost
(
expInfo
))
}
expInfo
,
err
=
connTest
.
Explain
(
"select 1"
,
ExtendedExplainType
,
TraditionalFormatExplain
)
err
=
common
.
GoldenDiff
(
func
()
{
fmt
.
Println
(
err
,
MySQLExplainQueryCost
(
expInfo
))
MySQLExplainQueryCost
(
expInfo
)
expInfo
,
err
=
connTest
.
Explain
(
"select 1"
,
TraditionalExplainType
,
JSONFormatExplain
)
fmt
.
Println
(
err
,
MySQLExplainQueryCost
(
expInfo
))
},
t
.
Name
(),
update
)
},
t
.
Name
(),
update
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
Error
(
err
)
...
...
database/mysql.go
浏览文件 @
d9f6ef72
...
@@ -279,6 +279,7 @@ func (db *Connector) dangerousQuery(query string) bool {
...
@@ -279,6 +279,7 @@ func (db *Connector) dangerousQuery(query string) bool {
"show"
,
"show"
,
"explain"
,
"explain"
,
"describe"
,
"describe"
,
"desc"
,
}
}
for
_
,
prefix
:=
range
whiteList
{
for
_
,
prefix
:=
range
whiteList
{
...
...
database/profiling_test.go
浏览文件 @
d9f6ef72
...
@@ -30,6 +30,10 @@ func TestProfiling(t *testing.T) {
...
@@ -30,6 +30,10 @@ func TestProfiling(t *testing.T) {
t
.
Error
(
err
)
t
.
Error
(
err
)
}
}
pretty
.
Println
(
rows
)
pretty
.
Println
(
rows
)
_
,
err
=
connTest
.
Profiling
(
"delete from film"
)
if
err
==
nil
{
t
.
Error
(
err
)
}
common
.
Log
.
Debug
(
"Exiting function: %s"
,
common
.
GetFunctionName
())
common
.
Log
.
Debug
(
"Exiting function: %s"
,
common
.
GetFunctionName
())
}
}
...
...
database/testdata/TestMySQLExplainQueryCost.golden
浏览文件 @
d9f6ef72
<nil>
<nil>
<nil>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录