# 阿里开发手册之 MySQL 编程规范借鉴

TIP

站在巨人的肩膀上,你会少走很多弯路。--鲁迅

# 建表规约

表名,字段名必须使用全小写字母,下划线,数字。禁止出现数字开头,禁止两个下划线中间中出现数字。

表名使用单数形式。

字段名不能使用 MySQL 保留字。如 asc, desc, match 等。

主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。

数据库字段修改的代价很大,无法进行预发布,所以建表时需认真对待,慎重考虑。

表达是否或者开关等概念的字段,必须使用 is_xxx 的命名方式。数据类型使用 unsigned tinyint(1)。

比如软删除字段: is_deleted 1 表示删除(正向,肯定);2 表示未删除(负向,否定)。

小数使用 decimal

  • float 和 double 类型的列,在做计算时,可能丢失精度,而 decimal 会精确计算。
  • float 和 double 在设置超过定义长度的数值时,会自动四舍五入,decimal会截断,并给出一条警告。

如果存储的字符串长度几乎相等,使用 char 定长字符串类型。

varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。

MySQL5.0 以上版本,varchar 最大可以存储 65535 字节数据(其中1-2个字节存储长度信息,还有 null 标志位)。此外,还受到行大小的限制,行长度不能超过 65535 字节。

在 UTF-8 编码下,一个汉字占 3 个字节,那么最大字符数不能超过 21845.

表定义中的 varchar(10) 表示的是 10 个字符,而不是字节数。

通用字段:

  • id: 类型为 bigint unsigned,自增,步长 1
  • gmt_create
  • gmt_modified
  • is_deleted

个人觉得创建时间和更新时间还是 created_at 和 updated_at 更好些,简单易理解。

表名命名采用 “业务名称+表的作用”形式。如 alipay_task。

库名与应用名称尽量一致。

如果更新表字段含义或对状态字段追加枚举值时,需要更新字段注释。

字段允许适当冗余,以提高查询性能,但必须考虑数据一致性,冗余字段应遵循:

  • 不是频繁修改的字段。
  • 不能是 varchar 超长字段,更不能是 text 类型字段。正例: 商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存储类目名称,避免关联查询。

单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。

合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。例如年龄字段或者状态枚举字段,在明确知道其范围的情况下,完全可以限定其类型长度。

# 索引规约

业务上具有唯一性的字段,即使是多字段的组合,也必须建成唯一索引。

  • 说明:唯一索引是保证业务数据唯一性的强有力保障,单纯靠应用层代码控制,很难做到 100% 唯一性。虽然索引会影响 insert 速度,但几乎可以忽略,它提高查询的速度更明显。

禁止超过 3 个表 join,需要 join 关联的字段,数据类型必须一致,必须有索引。

对 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。

对于blob,text,varchar的列必须使用前缀索引。

禁止左模糊或全模糊匹配。如果有需要,请走搜索引擎解决。

  • 说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。

如果有 order by 的场景,注意索引的有序性,避免出现 file sort 的情况影响查询性能。

  • 说明:where a=? and b=? order by c; 可以用到索引 a_b_c。如果索引中有范围查找,那么索引有序性无法利用,如 where a > 10 order by b; 索引 a_b 无法使用。

尽量利用覆盖索引来避免回表。

关于分页优化,MySQL 的 limit 查询并不是跳过 offset 行,而是取 offset + N 行,然后舍弃前 offset 行。当 offset 很大的时候,效率自然就低下。可以利用子查询以索引覆盖从而提升性能:

select t1.* from t1, (select id from t1 limit 1000000, 20) as t2 where t1.id = t2.id;
1

查询的类型,效率从低到高依次为:all -> index -> range -> ref -> eq_ref -> const。

sql 优化的目标:至少要达到 range 级别,const 最好。

  • 说明
    • all: 全表扫描,性能最差,数据量大时应避免此类查询。
    • index: 扫描全部索引,然后再回表取数据。
    • range: 扫描部分索引,通常出现在 between / 大小比较 / in 中。
    • ref: 使用了非唯一的索引。
    • eq_ref: 使用了主键或唯一索引。
    • const: 根据主键做等值查询。

建索引时,区分度高的字段放在左边。

防止因字段数据类型不同造成的隐式转换,造成命不中索引。