未验证 提交 62b08a21 编写于 作者: martianzhang's avatar martianzhang 提交者: GitHub

Merge pull request #130 from liipx/master

make RuleForbiddenSyntax more compatible with other companies
......@@ -1768,6 +1768,81 @@ func (q *Query4Audit) RuleSumNPE() Rule {
return rule
}
// RuleForbiddenTrigger FUN.007
func (q *Query4Audit) RuleForbiddenTrigger() Rule {
var rule = q.RuleOK()
// 由于vitess对某些语法的支持不完善,使得如创建临时表等语句无法通过语法检查
// 所以这里使用正则对触发器、临时表、存储过程等进行匹配
// 但是目前支持的也不是非常全面,有待完善匹配规则
// TODO TiDB 目前还不支持触发器、存储过程、自定义函数、外键
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?i)CREATE\s+TRIGGER\s+`),
}
for _, reg := range forbidden {
if reg.MatchString(q.Query) {
rule = HeuristicRules["FUN.007"]
if position := reg.FindIndex([]byte(q.Query)); len(position) > 0 {
rule.Position = position[0]
}
break
}
}
return rule
}
// RuleForbiddenProcedure FUN.008
func (q *Query4Audit) RuleForbiddenProcedure() Rule {
var rule = q.RuleOK()
// 由于vitess对某些语法的支持不完善,使得如创建临时表等语句无法通过语法检查
// 所以这里使用正则对触发器、临时表、存储过程等进行匹配
// 但是目前支持的也不是非常全面,有待完善匹配规则
// TODO TiDB 目前还不支持触发器、存储过程、自定义函数、外键
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?i)CREATE\s+PROCEDURE\s+`),
}
for _, reg := range forbidden {
if reg.MatchString(q.Query) {
rule = HeuristicRules["FUN.008"]
if position := reg.FindIndex([]byte(q.Query)); len(position) > 0 {
rule.Position = position[0]
}
break
}
}
return rule
}
// RuleForbiddenFunction FUN.009
func (q *Query4Audit) RuleForbiddenFunction() Rule {
var rule = q.RuleOK()
// 由于vitess对某些语法的支持不完善,使得如创建临时表等语句无法通过语法检查
// 所以这里使用正则对触发器、临时表、存储过程等进行匹配
// 但是目前支持的也不是非常全面,有待完善匹配规则
// TODO TiDB 目前还不支持触发器、存储过程、自定义函数、外键
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?i)CREATE\s+FUNCTION\s+`),
}
for _, reg := range forbidden {
if reg.MatchString(q.Query) {
rule = HeuristicRules["FUN.009"]
if position := reg.FindIndex([]byte(q.Query)); len(position) > 0 {
rule.Position = position[0]
}
break
}
}
return rule
}
// RulePatternMatchingUsage ARG.007
func (q *Query4Audit) RulePatternMatchingUsage() Rule {
var rule = q.RuleOK()
......@@ -1932,39 +2007,6 @@ func (idxAdv *IndexAdvisor) RuleUpdatePrimaryKey() Rule {
return rule
}
// RuleForbiddenSyntax CLA.017
func (q *Query4Audit) RuleForbiddenSyntax() Rule {
var rule = q.RuleOK()
// 由于vitess对某些语法的支持不完善,使得如创建临时表等语句无法通过语法检查
// 所以这里使用正则对触发器、临时表、存储过程等进行匹配
// 但是目前支持的也不是非常全面,有待完善匹配规则
// TODO TiDB 目前还不支持触发器、存储过程、自定义函数、外键
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?i)CREATE\s+TRIGGER\s+`),
regexp.MustCompile(`(?i)CREATE\s+TEMPORARY\s+TABLE\s+`),
regexp.MustCompile(`(?i)CREATE\s+VIEW\s+`),
regexp.MustCompile(`(?i)REPLACE\s+VIEW\s+`),
regexp.MustCompile(`(?i)CREATE\s+PROCEDURE\s+`),
regexp.MustCompile(`(?i)CREATE\s+FUNCTION\s+`),
}
for _, reg := range forbidden {
if reg.MatchString(q.Query) {
rule = HeuristicRules["CLA.017"]
if position := reg.FindIndex([]byte(q.Query)); len(position) > 0 {
rule.Position = position[0]
}
break
}
}
return rule
}
// RuleNestedSubQueries JOI.006
func (q *Query4Audit) RuleNestedSubQueries() Rule {
var rule = q.RuleOK()
......@@ -2826,6 +2868,57 @@ func (q *Query4Audit) RuleTableCharsetCheck() Rule {
return rule
}
// RuleForbiddenView TBL.006
func (q *Query4Audit) RuleForbiddenView() Rule {
var rule = q.RuleOK()
// 由于vitess对某些语法的支持不完善,使得如创建临时表等语句无法通过语法检查
// 所以这里使用正则对触发器、临时表、存储过程等进行匹配
// 但是目前支持的也不是非常全面,有待完善匹配规则
// TODO TiDB 目前还不支持触发器、存储过程、自定义函数、外键
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?i)CREATE\s+VIEW\s+`),
regexp.MustCompile(`(?i)REPLACE\s+VIEW\s+`),
}
for _, reg := range forbidden {
if reg.MatchString(q.Query) {
rule = HeuristicRules["TBL.006"]
if position := reg.FindIndex([]byte(q.Query)); len(position) > 0 {
rule.Position = position[0]
}
break
}
}
return rule
}
// RuleForbiddenTempTable TBL.007
func (q *Query4Audit) RuleForbiddenTempTable() Rule {
var rule = q.RuleOK()
// 由于vitess对某些语法的支持不完善,使得如创建临时表等语句无法通过语法检查
// 所以这里使用正则对触发器、临时表、存储过程等进行匹配
// 但是目前支持的也不是非常全面,有待完善匹配规则
// TODO TiDB 目前还不支持触发器、存储过程、自定义函数、外键
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?i)CREATE\s+TEMPORARY\s+TABLE\s+`),
}
for _, reg := range forbidden {
if reg.MatchString(q.Query) {
rule = HeuristicRules["TBL.007"]
if position := reg.FindIndex([]byte(q.Query)); len(position) > 0 {
rule.Position = position[0]
}
break
}
}
return rule
}
// RuleBlobDefaultValue COL.015
func (q *Query4Audit) RuleBlobDefaultValue() Rule {
var rule = q.RuleOK()
......
......@@ -1637,20 +1637,86 @@ func TestRuleHavingClause(t *testing.T) {
common.Log.Debug("Exiting function: %s", common.GetFunctionName())
}
// CLA.017
func TestRuleForbiddenSyntax(t *testing.T) {
// FUN.007
func TestRuleForbiddenTrigger(t *testing.T) {
common.Log.Debug("Entering function: %s", common.GetFunctionName())
sqls := []string{
`CREATE TRIGGER t1 AFTER INSERT ON work FOR EACH ROW INSERT INTO time VALUES(NOW());`,
}
for _, sql := range sqls {
q, _ := NewQuery4Audit(sql)
rule := q.RuleForbiddenTrigger()
if rule.Item != "FUN.007" {
t.Error("Rule not match:", rule.Item, "Expect : FUN.007")
}
}
common.Log.Debug("Exiting function: %s", common.GetFunctionName())
}
// FUN.008
func TestRuleForbiddenProcedure(t *testing.T) {
common.Log.Debug("Entering function: %s", common.GetFunctionName())
sqls := []string{
`CREATE PROCEDURE simpleproc (OUT param1 INT)`,
}
for _, sql := range sqls {
q, _ := NewQuery4Audit(sql)
rule := q.RuleForbiddenProcedure()
if rule.Item != "FUN.008" {
t.Error("Rule not match:", rule.Item, "Expect : FUN.008")
}
}
common.Log.Debug("Exiting function: %s", common.GetFunctionName())
}
// FUN.009
func TestRuleForbiddenFunction(t *testing.T) {
common.Log.Debug("Entering function: %s", common.GetFunctionName())
sqls := []string{
`CREATE FUNCTION hello (s CHAR(20));`,
}
for _, sql := range sqls {
q, _ := NewQuery4Audit(sql)
rule := q.RuleForbiddenFunction()
if rule.Item != "FUN.009" {
t.Error("Rule not match:", rule.Item, "Expect : FUN.009")
}
}
common.Log.Debug("Exiting function: %s", common.GetFunctionName())
}
// TBL.006
func TestRuleForbiddenView(t *testing.T) {
common.Log.Debug("Entering function: %s", common.GetFunctionName())
sqls := []string{
`create view v_today (today) AS SELECT CURRENT_DATE;`,
`CREATE VIEW v (col) AS SELECT 'abc';`,
`CREATE FUNCTION hello (s CHAR(20));`,
`CREATE PROCEDURE simpleproc (OUT param1 INT)`,
}
for _, sql := range sqls {
q, _ := NewQuery4Audit(sql)
rule := q.RuleForbiddenSyntax()
if rule.Item != "CLA.017" {
t.Error("Rule not match:", rule.Item, "Expect : CLA.017")
rule := q.RuleForbiddenView()
if rule.Item != "TBL.006" {
t.Error("Rule not match:", rule.Item, "Expect : TBL.006")
}
}
common.Log.Debug("Exiting function: %s", common.GetFunctionName())
}
// TBL.007
func TestRuleForbiddenTempTable(t *testing.T) {
common.Log.Debug("Entering function: %s", common.GetFunctionName())
sqls := []string{
"CREATE TEMPORARY TABLE `work` (`time` time DEFAULT NULL) ENGINE=InnoDB;",
}
for _, sql := range sqls {
q, _ := NewQuery4Audit(sql)
rule := q.RuleForbiddenTempTable()
if rule.Item != "TBL.007" {
t.Error("Rule not match:", rule.Item, "Expect : TBL.007")
}
}
......
......@@ -423,14 +423,6 @@ func init() {
Case: "update tbl set col=1",
Func: (*Query4Audit).RuleOK, // 该建议在indexAdvisor中给
},
"CLA.017": {
Item: "CLA.017",
Severity: "L2",
Summary: "不建议使用存储过程、视图、触发器、临时表等",
Content: `这些功能的使用在一定程度上会使得程序难以调试和拓展,更没有移植性,且会极大的增加出现 BUG 的概率。`,
Case: "CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;",
Func: (*Query4Audit).RuleForbiddenSyntax,
},
"COL.001": {
Item: "COL.001",
Severity: "L1",
......@@ -634,6 +626,30 @@ func init() {
Case: "SELECT SUM(COL) FROM tbl;",
Func: (*Query4Audit).RuleSumNPE,
},
"FUN.007": {
Item: "FUN.007",
Severity: "L1",
Summary: "不建议使用触发器",
Content: `触发器的执行没有反馈和日志,隐藏了实际的执行步骤,当数据库出现问题是,不能通过慢日志分析触发器的具体执行情况,不易发现问题。在MySQL中,触发器不能临时关闭或打开,在数据迁移或数据恢复等场景下,需要临时drop触发器,可能影响到生产环境。`,
Case: "CREATE TRIGGER t1 AFTER INSERT ON work FOR EACH ROW INSERT INTO time VALUES(NOW());",
Func: (*Query4Audit).RuleForbiddenTrigger,
},
"FUN.008": {
Item: "FUN.008",
Severity: "L1",
Summary: "不建议使用存储过程",
Content: `存储过程无版本控制,配合业务的存储过程升级很难做到业务无感知。存储过程在拓展和移植上也存在问题。`,
Case: "CREATE PROCEDURE simpleproc (OUT param1 INT);",
Func: (*Query4Audit).RuleForbiddenProcedure,
},
"FUN.009": {
Item: "FUN.009",
Severity: "L1",
Summary: "不建议使用自定义函数",
Content: `不建议使用自定义函数`,
Case: "CREATE FUNCTION hello (s CHAR(20));",
Func: (*Query4Audit).RuleForbiddenFunction,
},
"GRP.001": {
Item: "GRP.001",
Severity: "L2",
......@@ -1072,6 +1088,22 @@ func init() {
Case: "CREATE TABLE tbl (a int) DEFAULT CHARSET = latin1;",
Func: (*Query4Audit).RuleTableCharsetCheck,
},
"TBL.006": {
Item: "TBL.006",
Severity: "L1",
Summary: "不建议使用视图",
Content: `不建议使用视图`,
Case: "create view v_today (today) AS SELECT CURRENT_DATE;",
Func: (*Query4Audit).RuleForbiddenView,
},
"TBL.007": {
Item: "TBL.007",
Severity: "L1",
Summary: "不建议使用临时表",
Content: `不建议使用临时表`,
Case: "CREATE TEMPORARY TABLE `work` (`time` time DEFAULT NULL) ENGINE=InnoDB;",
Func: (*Query4Audit).RuleForbiddenTempTable,
},
}
}
......
......@@ -352,16 +352,6 @@ update tbl set col=1
```sql
update tbl set col=1
```
## 不建议使用存储过程、视图、触发器、临时表等
* **Item**:CLA.017
* **Severity**:L2
* **Content**:这些功能的使用在一定程度上会使得程序难以调试和拓展,更没有移植性,且会极大的增加出现 BUG 的概率。
* **Case**:
```sql
CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;
```
## 不建议使用 SELECT \* 类型查询
* **Item**:COL.001
......@@ -612,6 +602,36 @@ SELECT COUNT(1) FROM tbl;
```sql
SELECT SUM(COL) FROM tbl;
```
## 不建议使用触发器
* **Item**:FUN.007
* **Severity**:L1
* **Content**:触发器的执行没有反馈和日志,隐藏了实际的执行步骤,当数据库出现问题是,不能通过慢日志分析触发器的具体执行情况,不易发现问题。在MySQL中,触发器不能临时关闭或打开,在数据迁移或数据恢复等场景下,需要临时drop触发器,可能影响到生产环境。
* **Case**:
```sql
CREATE TRIGGER t1 AFTER INSERT ON work FOR EACH ROW INSERT INTO time VALUES(NOW());
```
## 不建议使用存储过程
* **Item**:FUN.008
* **Severity**:L1
* **Content**:存储过程无版本控制,配合业务的存储过程升级很难做到业务无感知。存储过程在拓展和移植上也存在问题。
* **Case**:
```sql
CREATE PROCEDURE simpleproc (OUT param1 INT);
```
## 不建议使用自定义函数
* **Item**:FUN.009
* **Severity**:L1
* **Content**:不建议使用自定义函数
* **Case**:
```sql
CREATE FUNCTION hello (s CHAR(20));
```
## 不建议对等值查询列使用 GROUP BY
* **Item**:GRP.001
......@@ -1152,3 +1172,23 @@ CREATE TABLE tbl (a int) AUTO_INCREMENT = 10;
```sql
CREATE TABLE tbl (a int) DEFAULT CHARSET = latin1;
```
## 不建议使用视图
* **Item**:TBL.006
* **Severity**:L1
* **Content**:不建议使用视图
* **Case**:
```sql
create view v_today (today) AS SELECT CURRENT_DATE;
```
## 不建议使用临时表
* **Item**:TBL.007
* **Severity**:L1
* **Content**:不建议使用临时表
* **Case**:
```sql
CREATE TEMPORARY TABLE `work` (`time` time DEFAULT NULL) ENGINE=InnoDB;
```
......@@ -32,7 +32,6 @@ advisor.Rule{Item:"CLA.013", Severity:"L3", Summary:"不建议使用 HAVING 子
advisor.Rule{Item:"CLA.014", Severity:"L2", Summary:"删除全表时建议使用 TRUNCATE 替代 DELETE", Content:"删除全表时建议使用 TRUNCATE 替代 DELETE", Case:"delete from tbl", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"CLA.015", Severity:"L4", Summary:"UPDATE 未指定 WHERE 条件", Content:"UPDATE 不指定 WHERE 条件一般是致命的,请您三思后行", Case:"update tbl set col=1", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"CLA.016", Severity:"L2", Summary:"不要 UPDATE 主键", Content:"主键是数据表中记录的唯一标识符,不建议频繁更新主键列,这将影响元数据统计信息进而影响正常的查询。", Case:"update tbl set col=1", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"CLA.017", Severity:"L2", Summary:"不建议使用存储过程、视图、触发器、临时表等", Content:"这些功能的使用在一定程度上会使得程序难以调试和拓展,更没有移植性,且会极大的增加出现 BUG 的概率。", Case:"CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.001", Severity:"L1", Summary:"不建议使用 SELECT * 类型查询", Content:"当表结构变更时,使用 * 通配符选择所有列将导致查询的含义和行为会发生更改,可能导致查询返回更多的数据。", Case:"select * from tbl where id=1", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.002", Severity:"L2", Summary:"INSERT/REPLACE 未指定列名", Content:"当表结构发生变更,如果 INSERT 或 REPLACE 请求不明确指定列名,请求的结果将会与预想的不同; 建议使用 “INSERT INTO tbl(col1,col2)VALUES ...” 代替。", Case:"insert into tbl values(1,'name')", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"COL.003", Severity:"L2", Summary:"建议修改自增 ID 为无符号类型", Content:"建议修改自增 ID 为无符号类型", Case:"create table test(`id` int(11) NOT NULL AUTO_INCREMENT)", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
......@@ -58,6 +57,9 @@ advisor.Rule{Item:"FUN.003", Severity:"L3", Summary:"使用了合并为可空列
advisor.Rule{Item:"FUN.004", Severity:"L4", Summary:"不建议使用 SYSDATE() 函数", Content:"SYSDATE() 函数可能导致主从数据不一致,请使用 NOW() 函数替代 SYSDATE()。", Case:"SELECT SYSDATE();", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"FUN.005", Severity:"L1", Summary:"不建议使用 COUNT(col) 或 COUNT(常量)", Content:"不要使用 COUNT(col) 或 COUNT(常量) 来替代 COUNT(*), COUNT(*) 是 SQL92 定义的标准统计行数的方法,跟数据无关,跟 NULL 和非 NULL 也无关。", Case:"SELECT COUNT(1) FROM tbl;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"FUN.006", Severity:"L1", Summary:"使用 SUM(COL) 时需注意 NPE 问题", Content:"当某一列的值全是 NULL 时,COUNT(COL) 的返回结果为0,但 SUM(COL) 的返回结果为 NULL,因此使用 SUM() 时需注意 NPE 问题。可以使用如下方式来避免 SUM 的 NPE 问题: SELECT IF(ISNULL(SUM(COL)), 0, SUM(COL)) FROM tbl", Case:"SELECT SUM(COL) FROM tbl;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"FUN.007", Severity:"L1", Summary:"不建议使用触发器", Content:"触发器的执行没有反馈和日志,隐藏了实际的执行步骤,当数据库出现问题是,不能通过慢日志分析触发器的具体执行情况,不易发现问题。在MySQL中,触发器不能临时关闭或打开,在数据迁移或数据恢复等场景下,需要临时drop触发器,可能影响到生产环境。", Case:"CREATE TRIGGER t1 AFTER INSERT ON work FOR EACH ROW INSERT INTO time VALUES(NOW());", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"FUN.008", Severity:"L1", Summary:"不建议使用存储过程", Content:"存储过程无版本控制,配合业务的存储过程升级很难做到业务无感知。存储过程在拓展和移植上也存在问题。", Case:"CREATE PROCEDURE simpleproc (OUT param1 INT);", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"FUN.009", Severity:"L1", Summary:"不建议使用自定义函数", Content:"不建议使用自定义函数", Case:"CREATE FUNCTION hello (s CHAR(20));", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"GRP.001", Severity:"L2", Summary:"不建议对等值查询列使用 GROUP BY", Content:"GROUP BY 中的列在前面的 WHERE 条件中使用了等值查询,对这样的列进行 GROUP BY 意义不大。", Case:"select film_id, title from film where release_year='2006' group by release_year", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"JOI.001", Severity:"L2", Summary:"JOIN 语句混用逗号和 ANSI 模式", Content:"表连接的时候混用逗号和 ANSI JOIN 不便于人类理解,并且MySQL不同版本的表连接行为和优先级均有所不同,当 MySQL 版本变化后可能会引入错误。", Case:"select c1,c2,c3 from t1,t2 join t3 on t1.c1=t2.c1,t1.c3=t3,c1 where id>1000", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"JOI.002", Severity:"L4", Summary:"同一张表被连接两次", Content:"相同的表在 FROM 子句中至少出现两次,可以简化为对该表的单次访问。", Case:"select tb1.col from (tb1, tb2) join tb2 on tb1.id=tb.id where tb1.id=1", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
......@@ -109,3 +111,5 @@ advisor.Rule{Item:"TBL.002", Severity:"L4", Summary:"请为表选择合适的存
advisor.Rule{Item:"TBL.003", Severity:"L8", Summary:"以DUAL命名的表在数据库中有特殊含义", Content:"DUAL表为虚拟表,不需要创建即可使用,也不建议服务以DUAL命名表。", Case:"create table dual(id int, primary key (id));", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"TBL.004", Severity:"L2", Summary:"表的初始AUTO_INCREMENT值不为0", Content:"AUTO_INCREMENT不为0会导致数据空洞。", Case:"CREATE TABLE tbl (a int) AUTO_INCREMENT = 10;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"TBL.005", Severity:"L4", Summary:"请使用推荐的字符集", Content:"表字符集只允许设置为utf8,utf8mb4", Case:"CREATE TABLE tbl (a int) DEFAULT CHARSET = latin1;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"TBL.006", Severity:"L1", Summary:"不建议使用视图", Content:"不建议使用视图", Case:"create view v_today (today) AS SELECT CURRENT_DATE;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
advisor.Rule{Item:"TBL.007", Severity:"L1", Summary:"不建议使用临时表", Content:"不建议使用临时表", Case:"CREATE TEMPORARY TABLE `work` (`time` time DEFAULT NULL) ENGINE=InnoDB;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}}
......@@ -352,16 +352,6 @@ update tbl set col=1
```sql
update tbl set col=1
```
## 不建议使用存储过程、视图、触发器、临时表等
* **Item**:CLA.017
* **Severity**:L2
* **Content**:这些功能的使用在一定程度上会使得程序难以调试和拓展,更没有移植性,且会极大的增加出现 BUG 的概率。
* **Case**:
```sql
CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;
```
## 不建议使用 SELECT \* 类型查询
* **Item**:COL.001
......@@ -612,6 +602,36 @@ SELECT COUNT(1) FROM tbl;
```sql
SELECT SUM(COL) FROM tbl;
```
## 不建议使用触发器
* **Item**:FUN.007
* **Severity**:L1
* **Content**:触发器的执行没有反馈和日志,隐藏了实际的执行步骤,当数据库出现问题是,不能通过慢日志分析触发器的具体执行情况,不易发现问题。在MySQL中,触发器不能临时关闭或打开,在数据迁移或数据恢复等场景下,需要临时drop触发器,可能影响到生产环境。
* **Case**:
```sql
CREATE TRIGGER t1 AFTER INSERT ON work FOR EACH ROW INSERT INTO time VALUES(NOW());
```
## 不建议使用存储过程
* **Item**:FUN.008
* **Severity**:L1
* **Content**:存储过程无版本控制,配合业务的存储过程升级很难做到业务无感知。存储过程在拓展和移植上也存在问题。
* **Case**:
```sql
CREATE PROCEDURE simpleproc (OUT param1 INT);
```
## 不建议使用自定义函数
* **Item**:FUN.009
* **Severity**:L1
* **Content**:不建议使用自定义函数
* **Case**:
```sql
CREATE FUNCTION hello (s CHAR(20));
```
## 不建议对等值查询列使用 GROUP BY
* **Item**:GRP.001
......@@ -1152,3 +1172,23 @@ CREATE TABLE tbl (a int) AUTO_INCREMENT = 10;
```sql
CREATE TABLE tbl (a int) DEFAULT CHARSET = latin1;
```
## 不建议使用视图
* **Item**:TBL.006
* **Severity**:L1
* **Content**:不建议使用视图
* **Case**:
```sql
create view v_today (today) AS SELECT CURRENT_DATE;
```
## 不建议使用临时表
* **Item**:TBL.007
* **Severity**:L1
* **Content**:不建议使用临时表
* **Case**:
```sql
CREATE TEMPORARY TABLE `work` (`time` time DEFAULT NULL) ENGINE=InnoDB;
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册