前言:
数据库对我们一个系统来说是非常重要的,数据库的相关信息是公司的核心数据信息,其内容的规范性会直接影响到公司的业务发展。我们每个人在使用数据库上有这不同的习惯,这对团队协作来说,不是那么友好。对数据库内部进行合理的规范设计,团队的所有人遵守这个规范,不仅能够降低系统的维护难度,同时一定程度上也可以提高系统的运行性能。
数据库对象命名规范
1、基本通用命名原则
- 命名使用带有含义的英文单词,避免以数字开头,多个单词组成时,禁止使用连字符。
- 只能使用小写英文字母、数字和下划线。
- 长度避免超过30个字符,尽量控制在20个字符以内。
- 避免使用MySQL的关键字、以及系统关键字(附录)。
2、表命名规范
- 表名不使用复数名词,表名应该仅仅表示表中的实体内容,不应该表示实体数量。
- 表名只能使用小写字母、数字和下划线,禁止以数字开头。
- 特殊情况下,需要用到临时表进行数据中转时,临时表的创建使用,需加temp_前缀,名称后面加上日期后缀。备份表的创建使用,需加bak_前缀,名称后面加上日期后缀。(临时表不能存储业务数据,确保两种表可以定期进行清理)
- 表名长度不要超过30个字符。
3、字段命名规范
- 字段名称由表达实际含义的英文单词或缩写组成。
- 表示是与否概念的字段,使用 is_xxx 的方式命名,数据类型使用unsigned tinyint( 1 表示是,0 表示否),例如:is_deleted,1 表示删除,0 表示未删除。
- 自增主键id字段使用id命名,不用增加前缀或后缀等信息,避免误以为将主键设置在业务字段上了使人产生误解,(主键id字段设计规范下文会讲到)
4、索引命名规范
- idx_<column_name>[..._<column_name>],各部分以下划线(_)分隔。
- 多个单词组成的column_name或多字段复合索引,取字段首个单词或者首字母缩写。
5、约束命名规范
- 主键约束: pk_开头,pk_<column_name>。
- unique唯一约束:uk_开头
- 禁止添加外键约束,不允许上线,如果业务逻辑需要,尽量从程序层面进行逻辑控制。
6、视图、函数、触发器、存储过程不允许上线
- 不建议在MySQL数据库内创建视图、函数、触发器或存储过程等对象,不允许上线,如果业务逻辑需要,尽量从外部程序层面进行逻辑控制。
- 如果临时需要新建存储过程处理生产问题,提交jira单到运维基建组,并且在处理完问题及时删除。
数据库对象设计规范
表设计规范
- 所有业务表必须包含主键id,主键与业务逻辑无关,禁止使用主键字段存储业务数据
- 每张表中必须包含的四个公共字段:
公共字段能够标记所有被人为干涉过的每条数据在什么时间被创建或修改过,以便DB底层的记录和历史的追溯,各位同学务必保证进入DB的所有表包含4个公共字段且未被业务挪用存储业务信息。
id
create_time(创建时间)
modified_time(修改时间)
is_deleted (删除标识,方便数据维护,进行逻辑删除,保留历史记录)
- 每张表建议不超过60个字段,字段过多时建议进行大表拆分以保障系统性能,例如拆分为一张查询表和一张详细内容表。
- 所有的字符存储与表示,均以 utf-8 编码
字段设计规范
- 每个业务字段需要有详细的字段注释,
- 自增ID建议使用bigint unsigned类型,频繁增删的表自增范围容易耗尽, 后期修改自增字段代价比较大。
[MySQL FAQ]系列 — 为什么InnoDB表要建议用自增列做主键
- 原则上所有字段必须定义为not null,且加上默认值default。
【相关说明】:
- not null一定程度上减少了存储开销,存储空间消耗比null更低。
- not null能有效避免索引失效,使SQL脚本的效率更高,利于整体全局环境的系统优化。
- null值影响判断,容易导致很多查询场景的查询结果出错。
- null值影响统计计算
- 禁止使用Blob、Text、Json类型字段(含MediumText、LongText、MediumBlob、LongBlob等),不允许上线。如有必要,考虑对大字段表做关联分离。
【相关说明】:
当InnoDB的文件格式(innodb_file_format)设置为Antelope,并且行格式为COMPACT 或 REDUNDANT 时,BLOB、TEXT或者长VARCHAR列只会将其前768字节存储在聚集索引页中。(最大768字节的作用是便于创建前缀索引/prefix index),其余更多的内容存储在额外的page里,哪怕只是多了一个字节。因此,所有列长度越短越好。在off-page中存储的BLOB、TEXT或者长VARCHAR列的page是独享的,不能共享。因此强烈不建议在一个表中使用多个长列。
- 小数类型建议使用decimal,禁止使用float和double(数据存储时时可能导致精度损失)。
- 枚举型的字段类型建议使用tinyint类型,尽量避免tinyint(1),以防踩坑。
索引设计规范
- 一般情况下创建的均为btree索引,不建议创建bitmap索引。
- 禁止重复索引,禁止冗余索引,禁止使用外键,禁止使用全文索引,不对过长的varchar字段建立索引,可考虑前缀索引,前缀索引长度建议不超过8个字符。
- 索引字段选择在where子句中出现,且选择性和过滤性高的字段,且和其他表关联的字段。建组合索引的时候,区分度最高 的在最左边
约束设计及其他规范
- 创建主键时,禁止使用组合主键。主键创建后不建议更新。
- 不允许外键与级联,如果业务逻辑需要,应该通过程序层面来控制。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险。
- 如果应用程序使用长连接来连接数据库,尽量具备重连机制,避免每次执行SQL时都检查DB。
视图、函数、触发器、存储过程不允许上线
禁止在数据库内创建视图、函数、触发器、存储过程等对象,不允许上线
数据库开发相关规范
关于count的使用
不要使用count(列名)或count(常量)来替代count(*),count(*)是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。count(*)会统计值为NULL的行,而count(列名)则不会统计。
关于DML/DDL操作
- in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控制在200个之内。
- TRUNCATE TABLE比DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE 无事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使用此语句。说明:TRUNCATE TABLE 在功能上与不带WHERE子句的 DELETE语句相同。
- 杜绝直接 SELECT * 读取全部字段,既影响查询的性能,又会对后期扩展造成不必要的麻烦。
- 在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。
- SQL语句不可以出现隐式类型转换(比如:select col from t where id=’1’)
- 禁止在where条件列上使用函数(会导致该列索引无效,从而全表扫描)
- 删除操作尽量使用逻辑删除而非物理删除。
- 数据查询或数据操作,关联表的上限尽量控制3张表内,禁止超过3张表的join,且join关联字段的数据类型必须保持一致。
附录
MySQL保留字
ADD | ALL | ALTER |
ANALYZE | AND | AS |
ASC | ASENSITIVE | BEFORE |
BETWEEN | BIGINT | BINARY |
BLOB | BOTH | BY |
CALL | CASCADE | CASE |
CHANGE | CHAR | CHARACTER |
CHECK | COLLATE | COLUMN |
CONDITION | CONNECTION | CONSTRAINT |
CONTINUE | CONVERT | CREATE |
CROSS | CURRENT_DATE | CURRENT_TIME |
CURRENT_TIMESTAMP | CURRENT_USER | CURSOR |
DATABASE | DATABASES | DAY_HOUR |
DAY_MICROSECOND | DAY_MINUTE | DAY_SECOND |
DEC | DECIMAL | DECLARE |
DEFAULT | DELAYED | DELETE |
DESC | DESCRIBE | DETERMINISTIC |
DISTINCT | DISTINCTROW | DIV |
DOUBLE | DROP | DUAL |
EACH | ELSE | ELSEIF |
ENCLOSED | ESCAPED | EXISTS |
EXIT | EXPLAIN | FALSE |
FETCH | FLOAT | FLOAT4 |
FLOAT8 | FOR | FORCE |
FOREIGN | FROM | FULLTEXT |
GOTO | GRANT | GROUP |
HAVING | HIGH_PRIORITY | HOUR_MICROSECOND |
HOUR_MINUTE | HOUR_SECOND | IF |
IGNORE | IN | INDEX |
INFILE | INNER | INOUT |
INSENSITIVE | INSERT | INT |
INT1 | INT2 | INT3 |
INT4 | INT8 | INTEGER |
INTERVAL | INTO | IS |
ITERATE | JOIN | KEY |
KEYS | KILL | LABEL |
LEADING | LEAVE | LEFT |
LIKE | LIMIT | LINEAR |
LINES | LOAD | LOCALTIME |
LOCALTIMESTAMP | LOCK | LONG |
LONGBLOB | LONGTEXT | LOOP |
LOW_PRIORITY | MATCH | MEDIUMBLOB |
MEDIUMINT | MEDIUMTEXT | MIDDLEINT |
MINUTE_MICROSECOND | MINUTE_SECOND | MOD |
MODIFIES | NATURAL | NOT |
NO_WRITE_TO_BINLOG | NULL | NUMERIC |
ON | OPTIMIZE | OPTION |
OPTIONALLY | OR | ORDER |
OUT | OUTER | OUTFILE |
PRECISION | PRIMARY | PROCEDURE |
PURGE | RAID0 | RANGE |
READ | READS | REAL |
REFERENCES | REGEXP | RELEASE |
RENAME | REPEAT | REPLACE |
REQUIRE | RESTRICT | RETURN |
REVOKE | RIGHT | RLIKE |
SCHEMA | SCHEMAS | SECOND_MICROSECOND |
SELECT | SENSITIVE | SEPARATOR |
SET | SHOW | SMALLINT |
SPATIAL | SPECIFIC | SQL |
SQLEXCEPTION | SQLSTATE | SQLWARNING |
SQL_BIG_RESULT | SQL_CALC_FOUND_ROWS | SQL_SMALL_RESULT |
SSL | STARTING | STRAIGHT_JOIN |
TABLE | TERMINATED | THEN |
TINYBLOB | TINYINT | TINYTEXT |
TO | TRAILING | TRIGGER |
TRUE | UNDO | UNION |
UNIQUE | UNLOCK | UNSIGNED |
UPDATE | USAGE | USE |
USING | UTC_DATE | UTC_TIME |
UTC_TIMESTAMP | VALUES | VARBINARY |
VARCHAR | VARCHARACTER | VARYING |
WHEN | WHERE | WHILE |
WITH | WRITE | X509 |
XOR | YEAR_MONTH | ZEROFILL |
心若有所向往,何惧道阻且长!
参考文档:
无尘老师PPT
我司DBA的数据库规约分享