一、基础规范
第一条:必须使用InnoDB存储引擎
 
第二条:必须使用utf8mb4字符集
utf8mb4是utf8的超集,emoji表情以及部分不常见汉字在utf8下会表现为乱码,故需要升级至utf8mb4。
 
第二条:数据表、数据字段必须加入中文注释
 
第三条:禁止使用存储过程、视图、触发器、Event
 
第四条:禁止存储大文件或者大照片
 
二、表和字段设计规范
第一条:禁止使用外键,如果有外键完整性约束,需要应用程序控制
 
第二条:必须把字段定义为NOT NULL并且提供默认值

a)null的列使索引/索引统计/值比较都更加复杂,对MySQL来说更难优化

b)null 这种类型MySQL内部需要进行特殊处理,增加数据库处理记录的复杂性;同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多

c)null值需要更多的存储空,无论是表还是索引中每行中的null的列都需要额外的空间来标识

d)对null 的处理时候,只能采用is null或is not null,而不能采用=、in、<、<>、!=、not in这些操作符号。如:where name!=’shenjian’,如果存在name为null值的记录,查询结果就不会包含name为null值的记录

 

第三条:禁止使用TEXT、BLOB类型

会浪费更多的磁盘和内存空间,非必要的大量的大字段查询会淘汰掉热数据,导致内存命中率急剧降低,影响数据库性能

 
第四条:禁止使用小数存储国币

曾经踩过这样的坑,100元分3天摊销,每天摊销100/3元,结果得到3个33.33。后来实施对账系统,始终有几分钱对不齐,郁闷了很久(不是几分钱的事,是业务方质疑的眼神让研发很不爽),最后发现是除法惹的祸。

解决方案:使用“分”作为单位,这样数据库里就是整数了。

 
三、索引设计规范
第一条:单表索引建议控制在5个以内
 
第二条:单索引字段数不允许超过5个
 
第三条:禁止在更新十分频繁、区分度不高的属性上建立索引

a)更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能

b)“性别”这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似

 

第四条:建立组合索引,必须把区分度高的字段放在前面

 

四、SQL使用规范

第一条:禁止使用SELECT *,只获取必要的字段,需要显示说明列属性

a)读取不需要的列会增加CPU、IO、NET消耗

b)不能有效的利用覆盖索引

c)使用SELECT *容易在增加或者删除字段后出现程序BUG

 

第二条:禁止使用INSERT INTO t_xxx VALUES(xxx),必须显示指定插入的列属性

 

第三条:禁止使用属性隐式转换

SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引

这个坑大家没踩过么?

phone是varchar类型,SQL语句带入的是整形,故不会命中索引,加个引号就好了:

 

SELECT uid FROM t_user WHERE phone=’13812345678’

 

第四条:禁止在WHERE条件的属性上使用函数或者表达式

SELECT uid FROM t_user WHERE from_unixtime(day)>='2017-02-15' 会导致全表扫描

正确的写法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2017-02-15 00:00:00')

 

 
第五条:禁止大表使用JOIN查询,禁止大表使用子查询
大表指的是数据量在1000万以上的表
 
第六条:只允许使用内网域名,而不是ip连接数据库
 
第七条:禁止使用OR条件,必须改为IN查询
 
 
第八条:禁止使用负向查询NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描

一般来说,WHERE过滤条件不会只带这么一个“负向查询条件”,还会有其他过滤条件,举个例子:查询沈剑已完成订单之外的订单(好拗口):

SELECT oid FROM t_order WHERE uid=123 AND status != 1;

 

订单表5000w数据,但uid=123就会迅速的将数据量过滤到很少的级别(uid建立了索引),此时再接上一个负向的查询条件就无所谓了,扫描的行数本身就会很少。

 

但如果要查询所有已完成订单之外的订单:

SELECT oid FROM t_order WHERE status != 1;

这就挂了,立马CPU100%,status索引会失效,负向查询导致全表扫描。

 

----本文转自58沈剑老师的微信,转载请注明出处