MySQL数据库设计规范推荐
第一章 总则
第1条 目的及适用范围
规范生产环境数据库设计,统一数据库设计标准。避免设计不合理造成重复犯错。
适用范围:Web技术部的全体开发。
第二章 命名规范
第1条 基本规范
(1) 原则:清晰明了,简洁准确,见名知意;
(2) 组成:英文字母, 下划线, 阿拉伯数字;
(3) 长度:最长64个字符,建议不超过30, 以免对后序的操作带来不便;
(4) 命名方式
-
名称中除下划线、数字的部分,要使用英文单词或英文短语或相应缩写,不推荐使用汉语拼音;
-
禁止使用MySQL关键字和保留字,见附录-关键字和保留字;
-
禁止出现数字开头;
-
英文字母使用小写形式,避免因操作系统或mysql服务配置的不同引起的问题;
-
名词使用单数;
-
多个单词用下划线分隔;
-
禁止两个下划线中间只出现数字;
第2条 具体规范
(1) 库命名
-
使用项目名缩写作为前缀,如游戏项目: game_xxx;
-
库名长度控制在10个字符内,超出10个字符时,尽量使用单词缩写;
-
备份库必须以bak_为前缀,以日期为后缀 例:bak_video_20180307;
-
临时库必须以tmp_为前缀,以日期为后缀 例:tmp_video_20180307;
(2) 表命名
-
用系统或模块的英文名的缩写作为前缀,优先使用模块名;
-
表名长度控制在15个字符内,超出15个字符时,尽量使用单词缩写;
-
备份表必须以bak_为前缀,以日期为后缀 例:bak_video_user_20180307;
-
临时表必须以tmp_为前缀,以日期为后缀 例:tmp_video_user_20180307;
(3) 字段命名
-
避免出现数字;
-
除外键或其它表的主键外,一般不需要添加前缀;
-
字段名长度控制在20个字符内,超出20个字符时,使用单词缩写;
(4) 索引命名
-
主键索引名为pk_字段名,pk_即 primary key;
-
非唯一索引 按照“idx_字段名称字段名称[字段名]”进行命名, idx_ 即 index;
-
唯一索引 按照“uk_字段名称字段名称[字段名]”进行命名, uk_即unique key;
-
如索引名过长,使用缩写;
第三章 注释
第1条 表注释
(1) 每个表必须要有注释;
(2) 描述数据表用途;
(3) 注释不超过30个字符;
第2条 字段注释
(1) 每个字段必须要有注释;
(2) 描述该字段的用途及可能存储的内容,字段的取值含义或者范围;
(3) 如果是枚举类型,将该字段中使用的内容都定义出来;
(4) 注释不超过30个字符;
第四章 MySQL字符集
第1条 推荐字符集
(1) 非特殊需求,所有字符存储与表示,均以utf-8编码;
(2) 如果需要存储Emoji表情,那么字段选择utf8mb4来进行存储;
第2条 创建对象的字符集
(1) 字符集和校对规则的4个级别 (从上到下,级别递减)
-
服务器级别;
-
数据库级别;
-
表级别、列级别;
-
连接级别;
(2) 更低级别的设置会继承高级别的设置;
(3) 通用规则
-
先为服务器或者数据库选择一个合理的字符集,然后根据不同的实际情况,让某个列选择自己的字符集;
-
字符集能表达的字符范围 utf8 > gbk > gb2312 > latin1;
-
字符集中的ci 为 Case Insensitive (大小写不敏感)的缩写, cs 为Case Sensitive (大小写敏感)的缩写;
-
字符集中 bin 表示用二进制存储数据,用编码值进行比较,区分大小写;
第3条 控制server和client端交互通信的字符集
(1) character_set_server:mysql server默认字符集;
(2) character_set_database:数据库默认字符集;
(3) character_set_client:MySQL server假定客户端发送的查询使用的字符集;
(4) character_set_connection:MySQL Server接收客户端发布的查询请求后,将其转换为character_set_connection变量指定的字符集;
(5) character_set_results:mysql server把结果集和错误信息转换为character_set_results指定的字符集,并发送给客户端;
(6) character_set_system:系统元数据(字段名等)字符集;
第五章 数据库设计
第1条 命名
见 库命名规范;
第2条 排序规则/校验规则 (collation)
(1) 尽量显式地设置字符集,而不是依赖于MySQL的默认设置;
(2) 如果不考虑占用空间及带宽因素,推荐使用utf-8;
第3条 数据库连接用完后,及时关闭
避免数据库连接数过大;
第六章 数据表设计
第1条 命名
见 表命名规范
第2条 排序规则/校验规则 (collation)
(1) 尽量显式地设置字符集;
(2) 结合业务使用英文字母大小写敏感/不敏感 的字符集;
第3条 表引擎
(1) 默认使用InnoDB;
(2) 从大量的select操作性能上考虑,日志及报表类数据表适合使用 MyISAM引擎,其余推荐使用InnoDB;
(3) 从支持事务,大量的insert, update 操作上来考虑,与交易、审核、金额相关的表用 InnoDB;
(4) 归档数据表(可查询,不更新删除),使用ARCHIVE引擎;
(5) 临时数据表,如数据量不大,不需要较高的数据安全生性,使用Memory引擎;
第4条 数据表存储内容
(1) 单表数据行数建议控制在1000万以内,或者数据表占用磁盘空间不超过10G;
(2) 不在数据库中存储文件,应使用对应文件的路径;
(3) 禁止存储明文密码;
第5条 字段
(1) 单表字段数建议不超过30;
(2) 字段数过多就进行垂直分表
-
冷热数据分离;
-
大字段分离;
-
常在一起作为条件和返回列的字段不分离;
第6条 表注释
如果要创建同表A一样的表结构B
推荐SQL语句:create table B like A, 或是先show create table A, 然后修改表名后,执行上一SQL结果中的表名,再执行;
避免使用 create table B as select * from B 来创建表(此操作只会创建表字段,而不会创建索引结构);
第7条 表注释
添加简洁明了的数据表功能说明, 详细见 表注释;
第七章 字段设计
第1条 命名
见 字段命名规范;
第2条 原则
(1) 用尽量少的存储空间来存储一个字段的数据;
(2) 表内的每一行都应当被唯一地标识;
(3) 同一库中,不同表中相同含义的字段,字段名保持一致;
(4) 如无备注,所有字段都设置not null, 并设置默认值;
(5) 字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:
-
不是频繁修改的字段;
-
不是 varchar 超长字段,更不能是 text 字段;
第3条 强制字段
(1) id 主键,类型为unsigned int (bigint),自增,步长为1;
(2) 如业务需要以下字段,推荐以下命名与字段类型:
-
create_time, 创建时间; update_time, 更新时间;
-
类型 推荐 datetime, 特点如下:
-
日期查询速度快;
-
可读性高;
-
无时区变换问题;
第4条 字段类型选取
(1) 能用tinyint 就不用int;
(2) 能用int 就不用char或varchar;
(3) 字段如果为非负数,必须是 unsigned;
(4) 如果存储的字符串长度相等,使用 char 定长字符串类型 ;
(5) 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint ( 1表示是,0表示否);
(6) 小数类型为 decimal,禁止使用 float 和 double;
说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储;
(7) varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率 ;
(8) 减少text,blob类型,如必要,需要将text,blob字段拆分后单独存储;
(9) 不建议使用enum类型,考虑使用tinyint类型替代;
(10)使用int unsigned存储IPV4 (使用php的 long2ip, ip2long 函数与 mysql 的 inet_aton, inet_aton) 进行转换;
(11)InnoDB引擎优先考虑使用varbinary存储大小写敏感的变长字符串或二进制内容;
第5条 表字段顺序
(1) 从前到后,按照字段的重要性和使用频率排列,id 作为第一列;
(2) 按照字段的功能归集排列,功能相似的字段相邻排列;
(3) create_time,update_time 放在最后;
第6条 字段注释
添加简洁明了的该列存储数据说明, 详细见 字段注释;
第八章 索引设计
第1条 命名
见 索引命名规范;
第2条 原则
(1) 最左前缀匹配原则;
(2) 为经常作为查询条件的字段建立索引;
(3) 为经常需要排序,分组的字段创建索引;
(4) 选择区分度高的列作为索引(组合索引除外)
-
区分度计算:count(distinct left(列名, 索引长度))/count(*);
-
在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可 ;
说明:索引的长度与区分度是一对矛盾体,长度越长,区分度越高;
(5) 使用前缀索引
-
索引的值过长,会影响查询速度;
-
要结合区分度,来选择合适长度的字段来建立索引;
(6) 如果字段事实上是与其它表的关键字相关联而未设计为外键引用,需建索引;
(7) 业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引;
(8) 多表关联查询时, 保证被关联的字段需要有索引;
(9) 有null 值存在的列,不要建索引;
(10)单张表中索引数量不超过5个;
(11)单个索引中的字段数不超过5个;
(12)禁止使用外键作为索引;
(13)索引长度不能超出限制
MyISAM: 所有索引字段定义长度的总和不能超过1000字节;
InnoDB:单一索引字段定义长度的总和不能超过767字节;
(14)使用explain 测试索引;
第3条 索引分类
(1) 唯一索引
-
业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引;
-
唯一索引的长度要和字段致;
-
禁止使用某字段的前N个字符做唯一索引;
(2) 组合索引
-
作为组合的查询条件、排序条件、分组条件中涉及的字段,可以建立组合索引;
-
建组合索引的时候,区分度最高的在最左边
a) 如果 where a=? and b=? ,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可;
b) 存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列;
- order by 最后的字段是组合索引的一部分,并且要放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能;
(3) 全文索引
-
在MySQL5.6以下,只有存储引擎为MyISAM的数据表支持全文检索,MySQL5.6及以上,InnoDB引擎表才开始支持全文检索;
-
MySQL全文索引只能对英文进行全文检索,本身不支持中文分词;
-
只支持在char, varchar, text字段上创建fulltext indexes;
-
MySQL全文检索时,所有FULLTEXT索引列必须使用相同的字符集;
-
MySQL全文检索时,默认检索长度为4,即关键词的长度必须大于5才能被捕获;
第九章 分库分表
第1条 分库分表的环境条件
(1) 单机负载过高;
(2) 数据表的数据量太大,正常的运维工作影响业务访问
-
对数据库备份时间过长;
-
DDL操作锁表时间长;
-
读写压力大;
(3) 数据表增长快,或无穷增长;
(4) 当前数据库、数据表设计不合理;
第2条 分库分表的原则
(1) 能不分就不分
-
分库分表增加了业务逻辑的复杂度;
-
优先从业务逻辑、实现方法上来解决问题;
(2) 出现在联表查询中的数据表,要分在一个库中;
(3) 避免造成跨库的事务;
第3条 分库分表方法
(1) 垂直拆分
-
根据业务按照模块或冷热数据(表)进行分库 (如微服务所使用的方式);
-
把数据表字段按照冷热数据(字段)分离、大数据(字段)分离、关联数据(字段)不分离的原则进行拆分;
(2) 水平拆分
-
如事先可估算出表能达到的量,可以通过一定的算法,计算每一条数据要存放的表名;
-
如表能达到的量级不能估算,则使用号段分表, 如 id 小于 1000w对应partition_1, id介于1000w - 2000w对就partition_2….;
第十章 附录
第1条 MySQL常用数据类型
(1) 整数类型
-
tinyint (1字节)
-
smallint (2字节)
-
mediumint (3字节)
-
int (4字节)
-
bigint (8字节)
(2) 定点类型
decimal (对DECIMAL(M,D) ,如果M>D,为M+2字节否则为D+2字节)
(3) 浮点类型
-
float (4字节)
-
double (8字节)
(4) 字符类型
-
char(Length) (Length字节)
-
varchar (0-255字节)
-
tinnytext (0-255字节)
-
text (0-65535字节)
-
mediumtext (0-16 777 215字节)
-
longtext (0-4 294 967 295字节)
-
tinyblob (0-255字节)
-
blob (0-65535字节)
-
mediumblob (0-16 777 215字节)
-
longblob (0-4 294 967 295字节)
(5) 日期类型
-
date (3字节) 格式:YYYY-MM-DD 范围:1000-01-01/9999-12-31
-
time (3字节) 格式:HH:MM:SS 范围: -838:59:59/838:59:59
-
year (1字节) 格式:YYYY 范围: 1901/2155
-
timestamp (4字节)范围:1970-01-01 00:00:00/2038-01-19 03:14:07 (GMT)
-
datetime (8字节)范围:1000-01-01 00:00:00/9999-12-31 23:59:59
(6) 枚举类型
-
enum 最多65535个成员
-
set 最多 64个成员
第2条 MySQL关键字与保留字
MySQL关键字与保留字 数量较多(MySQL5.7版本 622),不再一一列举,请见官方文档:https://dev.mysql.com/doc/refman/5.N/en/keywords.html#keywords-in-current-series