Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
六月暴雪飞梨花
soar
提交
a90d2064
S
soar
项目概览
六月暴雪飞梨花
/
soar
与 Fork 源项目一致
Fork自
Xiaomi / soar
通知
1
Star
0
Fork
0
代码
文件
提交
分支
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,发现更多精彩内容 >>
提交
a90d2064
编写于
12月 06, 2018
作者:
L
liipx
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add COL.007
上级
1bdc431a
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
85 addition
and
4 deletion
+85
-4
advisor/heuristic.go
advisor/heuristic.go
+26
-0
advisor/heuristic_test.go
advisor/heuristic_test.go
+22
-0
advisor/rules.go
advisor/rules.go
+8
-0
advisor/testdata/TestListHeuristicRules.golden
advisor/testdata/TestListHeuristicRules.golden
+10
-0
advisor/testdata/TestMergeConflictHeuristicRules.golden
advisor/testdata/TestMergeConflictHeuristicRules.golden
+1
-0
common/config.go
common/config.go
+4
-0
common/logger.go
common/logger.go
+4
-4
doc/heuristic.md
doc/heuristic.md
+10
-0
未找到文件。
advisor/heuristic.go
浏览文件 @
a90d2064
...
...
@@ -3246,6 +3246,32 @@ func (q *Query4Audit) RuleTooManyFields() Rule {
return
rule
}
// RuleMaxTextColsCount COL.007
func
(
q
*
Query4Audit
)
RuleMaxTextColsCount
()
Rule
{
var
textColsCount
int
var
rule
=
q
.
RuleOK
()
switch
q
.
Stmt
.
(
type
)
{
case
*
sqlparser
.
DDL
:
for
_
,
tiStmt
:=
range
q
.
TiStmt
{
switch
node
:=
tiStmt
.
(
type
)
{
case
*
tidb
.
CreateTableStmt
:
for
_
,
col
:=
range
node
.
Cols
{
switch
col
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeTinyBlob
:
textColsCount
++
}
}
}
}
}
if
textColsCount
>
common
.
Config
.
MaxTextColsCount
{
rule
=
HeuristicRules
[
"COL.007"
]
}
return
rule
}
// RuleAllowEngine TBL.002
func
(
q
*
Query4Audit
)
RuleAllowEngine
()
Rule
{
var
rule
=
q
.
RuleOK
()
...
...
advisor/heuristic_test.go
浏览文件 @
a90d2064
...
...
@@ -3091,6 +3091,28 @@ func TestRuleTooManyFields(t *testing.T) {
common
.
Log
.
Debug
(
"Exiting function: %s"
,
common
.
GetFunctionName
())
}
// COL.007
func
TestRuleMaxTextColsCount
(
t
*
testing
.
T
)
{
common
.
Log
.
Debug
(
"Entering function: %s"
,
common
.
GetFunctionName
())
sqls
:=
[]
string
{
"create table tbl (a int, b text, c blob, d text);"
,
}
common
.
Config
.
MaxColCount
=
0
for
_
,
sql
:=
range
sqls
{
q
,
err
:=
NewQuery4Audit
(
sql
)
if
err
==
nil
{
rule
:=
q
.
RuleMaxTextColsCount
()
if
rule
.
Item
!=
"COL.007"
{
t
.
Error
(
"Rule not match:"
,
rule
.
Item
,
"Expect : COL.007"
)
}
}
else
{
t
.
Error
(
"sqlparser.Parse Error:"
,
err
)
}
}
common
.
Log
.
Debug
(
"Exiting function: %s"
,
common
.
GetFunctionName
())
}
// TBL.002
func
TestRuleAllowEngine
(
t
*
testing
.
T
)
{
common
.
Log
.
Debug
(
"Entering function: %s"
,
common
.
GetFunctionName
())
...
...
advisor/rules.go
浏览文件 @
a90d2064
...
...
@@ -471,6 +471,14 @@ func init() {
Case
:
"CREATE TABLE tbl ( cols ....);"
,
Func
:
(
*
Query4Audit
)
.
RuleTooManyFields
,
},
"COL.007"
:
{
Item
:
"COL.007"
,
Severity
:
"L3"
,
Summary
:
"表中包含有太多的 text/blob 列"
,
Content
:
fmt
.
Sprintf
(
`表中包含超过%d个的 text/blob 列`
,
common
.
Config
.
MaxTextColsCount
),
Case
:
"CREATE TABLE tbl ( cols ....);"
,
Func
:
(
*
Query4Audit
)
.
RuleTooManyFields
,
},
"COL.008"
:
{
Item
:
"COL.008"
,
Severity
:
"L1"
,
...
...
advisor/testdata/TestListHeuristicRules.golden
浏览文件 @
a90d2064
...
...
@@ -409,6 +409,16 @@ CREATE TABLE tbl (col int) ENGINE=InnoDB;
* **Content**:表中包含有太多的列
* **Case**:
```sql
CREATE TABLE tbl ( cols ....);
```
## 表中包含有太多的 text/blob 列
* **Item**:COL.007
* **Severity**:L3
* **Content**:表中包含超过2个的 text/blob 列
* **Case**:
```sql
CREATE TABLE tbl ( cols ....);
```
...
...
advisor/testdata/TestMergeConflictHeuristicRules.golden
浏览文件 @
a90d2064
...
...
@@ -38,6 +38,7 @@ advisor.Rule{Item:"COL.003", Severity:"L2", Summary:"建议修改自增 ID 为
advisor.Rule{Item:"COL.004", Severity:"L1", Summary:"请为列添加默认值", Content:"请为列添加默认值,如果是 ALTER 操作,请不要忘记将原字段的默认值写上。字段无默认值,当表较大时无法在线变更表结构。", Case:"CREATE TABLE tbl (col int) ENGINE=InnoDB;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.005", Severity:"L1", Summary:"列未添加注释", Content:"建议对表中每个列添加注释,来明确每个列在表中的含义及作用。", Case:"CREATE TABLE tbl (col int) ENGINE=InnoDB;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.006", Severity:"L3", Summary:"表中包含有太多的列", Content:"表中包含有太多的列", Case:"CREATE TABLE tbl ( cols ....);", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.007", Severity:"L3", Summary:"表中包含有太多的 text/blob 列", Content:"表中包含超过2个的 text/blob 列", Case:"CREATE TABLE tbl ( cols ....);", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.008", Severity:"L1", Summary:"可使用 VARCHAR 代替 CHAR, VARBINARY 代替 BINARY", Content:"为首先变长字段存储空间小,可以节省存储空间。其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。", Case:"create table t1(id int,name char(20),last_time date)", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.009", Severity:"L2", Summary:"建议使用精确的数据类型", Content:"实际上,任何使用 FLOAT, REAL 或 DOUBLE PRECISION 数据类型的设计都有可能是反模式。大多数应用程序使用的浮点数的取值范围并不需要达到IEEE 754标准所定义的最大/最小区间。在计算总量时,非精确浮点数所积累的影响是严重的。使用 SQL 中的 NUMERIC 或 DECIMAL 类型来代替 FLOAT 及其类似的数据类型进行固定精度的小数存储。这些数据类型精确地根据您定义这一列时指定的精度来存储数据。尽可能不要使用浮点数。", Case:"CREATE TABLE tab2 (p_id BIGINT UNSIGNED NOT NULL,a_id BIGINT UNSIGNED NOT NULL,hours float not null,PRIMARY KEY (p_id, a_id))", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.010", Severity:"L2", Summary:"不建议使用 ENUM 数据类型", Content:"ENUM 定义了列中值的类型,使用字符串表示 ENUM 里的值时,实际存储在列中的数据是这些值在定义时的序数。因此,这列的数据是字节对齐的,当您进行一次排序查询时,结果是按照实际存储的序数值排序的,而不是按字符串值的字母顺序排序的。这可能不是您所希望的。没有什么语法支持从 ENUM 或者 check 约束中添加或删除一个值;您只能使用一个新的集合重新定义这一列。如果您打算废弃一个选项,您可能会为历史数据而烦恼。作为一种策略,改变元数据——也就是说,改变表和列的定义——应该是不常见的,并且要注意测试和质量保证。有一个更好的解决方案来约束一列中的可选值:创建一张检查表,每一行包含一个允许在列中出现的候选值;然后在引用新表的旧表上声明一个外键约束。", Case:"create table tab1(status ENUM('new','in progress','fixed'))", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
...
...
common/config.go
浏览文件 @
a90d2064
...
...
@@ -91,6 +91,7 @@ type Configuration struct {
MaxGroupByColsCount
int
`yaml:"max-group-by-cols-count"`
// 单条 SQL 中 GroupBy 包含列的最大数量
MaxDistinctCount
int
`yaml:"max-distinct-count"`
// 单条 SQL 中 Distinct 的最大数量
MaxIdxColsCount
int
`yaml:"max-index-cols-count"`
// 复合索引中包含列的最大数量
MaxTextColsCount
int
`yaml:"max-text-cols-count"`
// 表中含有的 text/blob 列的最大数量
MaxTotalRows
int64
`yaml:"max-total-rows"`
// 计算散粒度时,当数据行数大于 MaxTotalRows 即开启数据库保护模式,散粒度返回结果可信度下降
MaxQueryCost
int64
`yaml:"max-query-cost"`
// last_query_cost 超过该值时将给予警告
SpaghettiQueryLength
int
`yaml:"spaghetti-query-length"`
// SQL最大长度警告,超过该长度会给警告
...
...
@@ -167,6 +168,7 @@ var Config = &Configuration{
MaxGroupByColsCount
:
5
,
MaxDistinctCount
:
5
,
MaxIdxColsCount
:
5
,
MaxTextColsCount
:
2
,
MaxIdxBytesPerColumn
:
767
,
MaxIdxBytes
:
3072
,
MaxTotalRows
:
9999999
,
...
...
@@ -528,6 +530,7 @@ func readCmdFlags() error {
maxGroupByColsCount
:=
flag
.
Int
(
"max-group-by-cols-count"
,
Config
.
MaxGroupByColsCount
,
"MaxGroupByColsCount, 单条 SQL 中 GroupBy 包含列的最大数量"
)
maxDistinctCount
:=
flag
.
Int
(
"max-distinct-count"
,
Config
.
MaxDistinctCount
,
"MaxDistinctCount, 单条 SQL 中 Distinct 的最大数量"
)
maxIdxColsCount
:=
flag
.
Int
(
"max-index-cols-count"
,
Config
.
MaxIdxColsCount
,
"MaxIdxColsCount, 复合索引中包含列的最大数量"
)
maxTextColsCount
:=
flag
.
Int
(
"max-texst-cols-count"
,
Config
.
MaxTextColsCount
,
"MaxTextColsCount, 表中含有的 text/blob 列的最大数量"
)
maxTotalRows
:=
flag
.
Int64
(
"max-total-rows"
,
Config
.
MaxTotalRows
,
"MaxTotalRows, 计算散粒度时,当数据行数大于MaxTotalRows即开启数据库保护模式,不计算散粒度"
)
maxQueryCost
:=
flag
.
Int64
(
"max-query-cost"
,
Config
.
MaxQueryCost
,
"MaxQueryCost, last_query_cost 超过该值时将给予警告"
)
spaghettiQueryLength
:=
flag
.
Int
(
"spaghetti-query-length"
,
Config
.
SpaghettiQueryLength
,
"SpaghettiQueryLength, SQL最大长度警告,超过该长度会给警告"
)
...
...
@@ -626,6 +629,7 @@ func readCmdFlags() error {
Config
.
MaxIdxColsCount
=
16
}
Config
.
MaxTextColsCount
=
*
maxTextColsCount
Config
.
MaxIdxBytesPerColumn
=
*
maxIdxBytesPerColumn
Config
.
MaxIdxBytes
=
*
maxIdxBytes
if
*
allowCharsets
!=
""
{
...
...
common/logger.go
浏览文件 @
a90d2064
...
...
@@ -43,11 +43,11 @@ func LoggerInit() {
func
()
{
_
=
Log
.
DelLogger
(
logs
.
AdapterFile
)
}()
logConfig
:=
map
[
string
]
interface
{}{
"filename"
:
Config
.
LogOutput
,
"level"
:
7
,
"level"
:
7
,
"maxlines"
:
0
,
"maxsize"
:
0
,
"daily"
:
false
,
"maxdays"
:
0
,
"maxsize"
:
0
,
"daily"
:
false
,
"maxdays"
:
0
,
}
logConfigJson
,
_
:=
json
.
Marshal
(
logConfig
)
err
:=
Log
.
SetLogger
(
logs
.
AdapterFile
,
fmt
.
Sprintf
(
string
(
logConfigJson
)))
...
...
doc/heuristic.md
浏览文件 @
a90d2064
...
...
@@ -409,6 +409,16 @@ CREATE TABLE tbl (col int) ENGINE=InnoDB;
*
**Content**
:表中包含有太多的列
*
**Case**
:
```
sql
CREATE
TABLE
tbl
(
cols
....);
```
## 表中包含有太多的 text/blob 列
*
**Item**
:COL.007
*
**Severity**
:L3
*
**Content**
:表中包含超过2个的 text/blob 列
*
**Case**
:
```
sql
CREATE
TABLE
tbl
(
cols
....);
```
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录