CTO要我把这份MySQL规范贴在工位上!
因为工作岗位的原因,负责制定了关于后端组数据库的规约规范,作为所有产品线的规范,历经几版的修改,最终形成下边的文本。
规范在整个后端执行也有大半年的时间,对于整个团队在开发阶段就减少不恰当的建表语句、错误 SQL、错误的索引有积极的意义,故分享出来给大家参考。
下边分为建表规约、SQL 规约、索引规约三个部分,每部分的每一条都有强制、建议两个级别,大家在参考时,根据自己公司的情况来权衡。
建表规约
【强制】:①存储引擎必须使用 InnoDB
解读:InnoDB 支持事物、行级锁、并发性能更好,CPU 及内存缓存页优化使得资源利用率更高。
【强制】:②每张表必须设置一个主键 ID,且这个主键 ID 使用自增主键(在满足需要的情况下尽量短),除非在分库分表环境下
解读:由于 InnoDB 组织数据的方式决定了需要有一个主键,而且若是这个主键 ID 是单调递增的可以有效提高插入的性能,避免过多的页分裂、减少表碎片提高空间的使用率。
而在分库分表环境下,则需要统一来分配各个表中的主键值,从而避免整个逻辑表中主键重复。
【强制】:③必须使用 utf8mb4 字符集
解读:在 MySQL 中的 UTF-8 并非“真正的 UTF-8”,而 utf8mb4”才是真正的“UTF-8”。
【强制】:④数据库表、表字段必须加入中文注释
解读:大家都别懒。
【强制】:⑤库名、表名、字段名均小写,下划线风格,不超过 32 个字符,必须见名知意,禁止拼音英文混用
解读:约定。
【强制】:⑥单表列数目必须小于 30,若超过则应该考虑将表拆分
解读:单表列数太多使得 MySQL 服务器处理 InnoDB 返回数据之间的映射成本太高。
【强制】:⑦禁止使用外键,如果有外键完整性约束,需要应用程序控制
解读:外键会导致表与表之间耦合,UPDATE 与 DELETE 操作都会涉及相关联的表,十分影响 SQL 的性能,甚至会造成死锁。
【强制】:⑧必须把字段定义为 NOT NULL 并且提供默认值
解读:
NULL 的列使索引/索引统计/值比较都更加复杂,对 MySQL 来说更难优化。
NULL 这种类型 MySQL 内部需要进行特殊处理,增加数据库处理记录的复杂性;同等条件下,表中有较多空字段的时候,数据库的处理性能会降低很多。
NULL 值需要更多的存储空,无论是表还是索引中每行中的 NULL 的列都需要额外的空间来标识。
【强制】:⑨禁用保留字,如 DESC、RANGE、MARCH 等
解读:请参考 MySQL 官方保留字。
这两种类型的都能表达"yyyy-MM-dd HH:mm:ss"格式的时间,TIMESTAMP 只需要占用 4 个字节的长度,可以存储的范围为(1970-2038)年,在各个时区,所展示的时间是不一样的。
而 DATETIME 类型占用 8 个字节,对时区不敏感,可以存储的范围为(1001-9999)年。
SQL 规约
【建议】:①为了充分利用缓存,不允许使用自定义函数、存储函数、用户变量
解读:如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL 库中的系统表,其查询结果都不会被缓存。
比如函数 NOW() 或者 CURRENT_DATE() 会因为不同的查询时间,返回不同的查询结果。
读取不需要的列会增加 CPU、IO、NET 消耗。
不能有效的利用覆盖索引。
解读:假设我们在手机号列上添加了索引,然后执行下面的 SQL 会发生什么?
explain SELECT user_name FROM parent WHERE phone=13812345678;很明显就是索引不生效,会全表扫描。
索引规约
解读:覆盖查询即是查询只需要通过索引即可拿到所需 DATA,而不再需要再次回表查询,所以效率相对很高。
我们在使用 EXPLAIN 的结果,extra 列会出现:"using index"。这里也要强调一下不要使用“SELECT * ”,否则几乎不可能使用到覆盖索引。
解读:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,若长度为 20 的索引,区分度会高达 90% 以上,则可以考虑创建长度例为 20 的索引,而非全字段索引。
例如可以使用 SELECT COUNT(DISTINCT LEFT(lesson_code, 20))/COUNT(*) FROM lesson;来确定 lesson_code 字段字符长度为 20 时文本区分度。
【建议】:⑦如果有 ORDER BY 的场景,请注意利用索引的有序性
ORDER BY 最后的字段是联合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。
假设有查询条件为 WHERE a=? and b=? ORDER BY c;存在索引:a_b_c,则此时可以利用索引排序。
反例:在查询条件中包含了范围查询,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b;索引 a_b 无法排序。
《High.Performance.MySQL.3rd.Edition》
《阿里巴巴java开发手册》
作者:浮雷
编辑:陶家龙
出处:https://juejin.im/post/6871969929365553165
更多精彩文章