Java开发者必需要知道的MySQL规范

规范在整个后端执行也有大半年的时间,对于整个团队在开发阶段就减小不恰当的建表语句、错误 SQL、错误的索引有积极的意义,故分享出来给你们参考。java


下边分为建表规约、SQL 规约、索引规约三个部分,每部分的每一条都有强制、建议两个级别,你们在参考时,根据本身公司的状况来权衡。数据库


建表规约后端


【强制】存储引擎必须使用 InnoDB缓存


解读:InnoDB 支持事物、行级锁、并发性能更好,CPU 及内存缓存页优化使得资源利用率更高。服务器


【强制】:②每张表必须设置一个主键 ID,且这个主键 ID 使用自增主键(在知足须要的状况下尽可能短),除非在分库分表环境下微信


解读:因为 InnoDB 组织数据的方式决定了须要有一个主键,并且如果这个主键 ID 是单调递增的能够有效提升插入的性能,避免过多的页分裂、减小表碎片提升空间的使用率。
并发


而在分库分表环境下,则须要统一来分配各个表中的主键值,从而避免整个逻辑表中主键重复。app


【强制】:③必须使用 utf8mb4 字符集less


解读:在 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 等等。


参考资料:
  • 《High.Performance.MySQL.3rd.Edition》

  • 《阿里巴巴java开发手册》


做者:浮雷

编辑:陶家龙

出处:https://juejin.im/post/6871969929365553165


更多好文敬请关注公众号


本文分享自微信公众号 - JAVA开发者课堂(leechence)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索