共计 3252 个字符,预计需要花费 9 分钟才能阅读完成。
因为工作岗位的起因,负责制订了对于后端组数据库的规约标准,作为所有产品线的标准,历经几版的批改,最终造成下边的文本。
标准在整个后端执行也有大半年的工夫,对于整个团队在开发阶段就缩小不失当的建表语句、谬误 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 官网保留字。
【强制】:⑩如果存储的字符串长度简直相等,应用 CHAR 定长字符串类型
解读:可能缩小空间碎片,节俭存储空间。
【倡议】:⑪ 在一些场景下,思考应用 TIMESTAMP 代替 DATETIME
解读:
这两种类型的都能表白 ”yyyy-MM-dd HH:mm:ss” 格局的工夫,TIMESTAMP 只须要占用 4 个字节的长度,能够存储的范畴为(1970-2038)年,在各个时区,所展现的工夫是不一样的。
而 DATETIME 类型占用 8 个字节,对时区不敏感,能够存储的范畴为(1001-9999)年。
【倡议】:⑫当心主动生成的 Schema,倡议所有的 Schema 手动编写
解读:对于一些数据库客户端不要太过信赖。
SQL 规约
【倡议】:①为了充分利用缓存,不容许应用自定义函数、存储函数、用户变量
解读:如果查问中蕴含任何用户自定义函数、存储函数、用户变量、长期表、MySQL 库中的零碎表,其查问后果都不会被缓存。
比方函数 NOW() 或者 CURRENT_DATE() 会因为不同的查问工夫,返回不同的查问后果。
【强制】:②在查问中指定所需的列,而不是间接应用“*”返回所有的列
解读:
读取不须要的列会减少 CPU、IO、NET 耗费。
不能无效的利用笼罩索引。
【强制】:③不容许应用属性隐式转换
解读:假如咱们在手机号列上增加了索引,而后执行上面的 SQL 会产生什么?
explain SELECT user_name FROM parent WHERE phone=13812345678;很显著就是索引不失效,会全表扫描。
【倡议】:④在 WHERE 条件的属性上应用函数或者表达式
解读:MySQL 无奈主动解析这种表达式,无奈应用到索引。
【强制】:⑤禁止应用外键与级联,所有外键概念必须在应用层解决
解读:外键与级联更新实用于单机低并发,不适宜分布式、高并发集群; 级联更新是强阻塞,存在数据库更新风暴的危险;外键影响数据库的插入速度。
【倡议】:⑥应尽量避免在 WHERE 子句中应用 or 作为连贯条件
解读:依据状况能够抉择应用 UNION ALL 来代替 OR。
【强制】:⑦不容许应用 % 结尾的含糊查问
解读:依据索引的最左前缀原理,% 结尾的含糊查问无奈应用索引,能够应用 ES 来做检索。
索引规约
【倡议】:①防止在更新比拟频繁、区分度不高的列上独自建设索引
解读:区分度不高的列独自创立索引的优化成果很小,然而较为频繁的更新则会让索引的保护老本更高。
【强制】:②JOIN 的表不容许超过五个。须要 JOIN 的字段,数据类型必须相对统一; 多表关联查问时,保障被关联的字段须要有索引
解读:太多表的 JOIN 会让 MySQL 的优化器更难衡量出一个“最佳”的执行打算(可能性为表数量的阶乘),同时要留神关联字段的类型、长度、字符编码等等是否统一。
【强制】:③在一个联结索引中,若第一列索引区分度等于 1,那么则不须要建设联结索引
解读:索引通过第一列就可能齐全定位的数据,所以联结索引的后边局部是不须要的。
【强制】:④建设联结索引时,必须将区分度更高的字段放在右边
解读:区分度更高的列放在右边,可能在一开始就无效的过滤掉无用数据。进步索引的效率,相应咱们在 Mapper 中编写 SQL 的 WHERE 条件中有多个条件时,须要先看看以后表是否有现成的联结索引间接应用,留神各个条件的程序尽量和索引的程序统一。
【倡议】:⑤利用笼罩索引来进行查问操作,防止回表
解读:笼罩查问即是查问只须要通过索引即可拿到所需 DATA,而不再须要再次回表查问,所以效率绝对很高。
咱们在应用 EXPLAIN 的后果,extra 列会呈现:”using index”。这里也要强调一下不要应用“SELECT *”,否则简直不可能应用到笼罩索引。
【倡议】:⑥在较长 VARCHAR 字段,例如 VARCHAR(100) 上建设索引时,应指定索引长度,没必要对全字段建设索引,依据理论文本区分度决定索引长度即可
解读:索引的长度与区分度是一对矛盾体,个别对字符串类型数据,若长度为 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 无奈排序。
【倡议】:⑧在 Where 中索引的列不能某个表达式的一部分,也不能是函数的参数
解读:即是某列上曾经增加了索引,然而若此列成为表达式的一部分、或者是函数的参数,MySQL 无奈将此列独自解析进去,索引也不会失效。
【倡议】:⑨咱们在 Where 条件中应用范畴查问时,索引最多用于一个范畴条件,超过一个则后边的不走索引
解读:MySQL 可能应用多个范畴条件里边的最右边的第一个范畴查问,然而后边的范畴查问则无奈应用。
【倡议】:⑩在多个表进行外连贯时,表之间的关联字段类型必须完全一致
解读:当两个表进行 Join 时,字段类型若没有完全一致,则加索引也不会失效,这里的完全一致包含但不限于字段类型、字段长度、字符集、Collection 等等。