一、总则
1.1 目的
为使公司内部MySQL
项目数据库设计遵循标准化、统一化原则,便于每个开发工程师了解不同业务逻辑,同时降低bug产生量和问题排查时间。最终是的内部所有MySQL
项目数据可设计条理有序,关系明确,特制订本使用规范。
1.2 适用范围
本规范适用于内部所有MySQL
项目数据库设计。
1.3 管理职责
1. 开发项目组
- 开发工程师依据该规范设计数据库
- 各项目组技术负责人先内部审核数据库设计方案。
2. 运维组
- 由运维部严格把关各个项目组初审提交的数据库设计方案。对于违反该规范,数据库管理员须要求其重新设计或修改,对于符合该规范可在服务器执行。
3. 操作
- 禁止明文传播数据库账号和密码。
- 禁止开发工程师通过应用账号登录生产数据库
- 禁止应用在服务器安装MySQL客户端(可以安装开发包)
- 禁止开发人员在SQL中添加Hint,Hint只能由DBA审核后添加。
- 禁止使用悲观锁定,即读锁 select … for update。
- 禁止在开发代码中使用 DDL 语句,比如truncate,alert table …等
- 禁止DML语句的where条件中包含恒真条件(如:1=1)。
二、具体规范
2.1 数据库版本
生产环境默认使用MySQL 5.7
(与现有线上环境一致),不建议使用其他版本的数据库,如有特殊需求,需要和数据库管理员协商确认。
2.2 存储引擎
使用Innodb存储引擎,5.5版本开始mysql默认存储引擎就是InnoDB,5.7版本开始,系统表都放弃MyISAM了。有特殊需要可使用其他存储引擎,需要和数据库管理员协商确认。
2.3 字符集
凡涉及数据库表结构须统一utf8mb4
字符集(utf8mb4
支持emoji
表情),包括客户端和服务端。
-
客户端字符集
character_set_client = utf8mb4;扫描二维码关注公众号,回复: 4391237 查看本文章 -
连接层字符集
character_set_connection = utf8mb4; -
数据库默认字符集
character_set_database = utf8mb4; -
默认内部操作字符集
character_set_server = utf8mb4; -
系统元数据(字段名等)字符集
character_set_system = utf8mb4; -
查询结果字符集
character_set_results = utf8mb4;
2.4 命名规则
总则
数据库命名规则必须遵循如下规则:
- 数据库对象名仅可包含小写英文字母、数字、下划线( _ )三类字符,并以英文字母开头。
- 库名、表名、字段名禁止超过32个字符.
- 多个单词之间用下划线( _ )分隔,不允许使用(-)。
- 数据库对象命名禁止使用
MySQL
保留字。 - 日志表表名必须以log为前缀,并以日期为后缀
- 临时库库名、临时表表名必须以tmp为前缀,并以日期为后缀
- 备份库库名、备份表表吗必须以bak为前缀,并以日期为后缀
- 对象名称长度若超过限制,则使用简写/缩写命名。
- 所有表必须加注释
- 所有表字段必须加注释
- 单表字段不超过30个,再多的话考虑垂直分表
- 单表的索引不能超过5个
- 所有表都必须要指定主键(因引擎InnoDB)
下面我们以演示表进行具体说明
CREATE TABLE `prefix_test` (
`test_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`test_sn` char(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '对外sn',
`test_name` varchar(32) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '名称',
`test_type` tinyint(4) unsigned NOT NULL DEFAULT 1 COMMENT '类型 1-需求 2-开发 3-测试 4-上线 5-bug 6-debug 7-其他',
`test_status` tinyint(4) unsigned NOT NULL DEFAULT 1 COMMENT '状态 1-未开始 2-启动中 3-验证中 4-已验证 5-已结束 6-已过期',
`uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
`oid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '订单ID',
`cate_id` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '分类',
`money` decimal(10,2) unsigned NOT NULL DEFAULT 0.00 COMMENT '金额',
`start_year` year(4) NOT NULL DEFAULT 0000 COMMENT '开始年',
`content` text CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '内容',
`is_del` tinyint(4) unsigned NOT NULL DEFAULT 2 COMMENT '删除标记1是2否',
`create_uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '创建者',
`update_uid` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '更新者(最后)',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`test_id`),
UNIQUE KEY `uk_test_sn` (`test_sn`) USING BTREE COMMENT '对外sn',
KEY `fk_user_uid` (`uid`) USING BTREE COMMENT '用户ID(外键)',
KEY `fk_order_oid` (`oid`) USING BTREE COMMENT '订单ID(外键)',
KEY `fk_cate_id` (`cate_id`) USING BTREE COMMENT '分类ID(外键)'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='演示表'
1. 数据库命名规则
库名称命名必须遵循易懂、简单、无二义性原则,必须遵循如下规则:
- 数据库对象名仅可包含小写英文字母、数字、下划线( _ )三类字符,并以英文字母开头。
- 禁止使用
MySQL
保留字。 - 多个单词之间用下划线( _ )分隔。
- 数据库以db_前缀+站点名_前缀及其所服务的应用名称命名。
2. 表名称命名规则
表名称命名必须遵循易懂、简单、无二义性原则,必须遵循如下规则:
- 小写字母,数字和半角下划线组合。
- 禁止使用
MySQL
保留字。 - 表命名根据表的业务逻辑用半角下划线拼接,相同业务表须带有相同表头标识。
3. 字段命名规则
字段名称必须遵循易懂、简单、无二义性原则,必须遵循如下规则:
- 小写字母,数字和半角下划线组合。
- 禁止使用
MySQL
保留字。 - 每个非定义表(表内容经常变更)必须包含
create_time
和update_time
,根据时间戳更新。 - 每个非定义表(表内容经常变更)必须包含
create_id
和update_id
用于追溯创建和修改来源。 - 上述四个字段的顺序为:
create_id
,create_time
,update_id
,update_time
。 - 布尔意义的字段以
is_
作为前缀,或_flag
为后缀,前接动词。如:表示逻辑删除意义的字段可命名为delete_flag、is_delete - 日期字段使用
filed_date
类型date
,filed_year
类型year
- 日期时间字段使用
filed_time
类型datetime
- 状态字段使用
filed_status
类型tinyint
,注释中必须明确列出各状态值的说明 - 类型字段使用
filed_type
类型tinyint
- 类型字段使用
filed_cate
类型int
外键与cate
表 - 浮点数字段使用
decimal
类型(float, double记录数据不精确) uid
、oid
因行业的默认为user_id,order_id的简写,其他简写慎用- 同一意义的字段定义必须相同;如:user_id在不同表类型
int(11) unsigned
必须相同
4. 索引命名规则
为了便于识别索引和代码中检索索引,现统一按如下规则命名索引名称:
- 索引一idx_表名缩写_字段名缩写
idx_tablename_columnnames
方式命名 - 组合索引以idx_表名缩写_字段名1_字段名2
idx_tablename_columnname1_columnname2
方式命名 - 唯一索引以uk_表名缩写_字段缩写
uk_tablelname_columnames
方式命名 - 外键以fk_表名1(自身表)缩写_表名2(关联表)缩写_字段缩写
fk_tablename1_tablename2_columname1_columname2
。不建议使用外键,将影响数据库性能。 - 单表的索引总量不超过5个
2.5 字段类型选择
字段类型选择遵循:能占一个字节绝不占两个字节。因此在设计表结构时需要预估字段值范围。
1. 数字类型
- 整数
类型 | 字节 | 范围 | |
---|---|---|---|
tinyint | 1 | (-128, 127) (0, 255) | 小整数值 |
smallint | 2 | (-32 768, 32 767) (0, 65 535) | 大整数值 |
mediuming | 3 | (-8388608, 8388607)(0, 16 777 215) | 大整数值 |
int/integer | 4 | (-2 147 483 648, 2 147 483 647)(0, 4 294 967 295) | 大整数值 |
bigint | 8 | (-9 233 372 036 854 775 808, 9 223 372 036 854 775 807) (0, 18 446 744 073 709 551 615) | 极大整数值 |
对于自增字段,如果记录经常做物理删除(delete)或记录数未来可能会超过21亿必须用bigint。
默认使用unsigned类型。
对于表示状态、类型、种类一律用tinyint,依据域范围合理选择smallint、mediumint。
- 小数
类型 | 字节 | 说明 |
---|---|---|
float(m, n) | 4 | 单精度浮点数值 ,其中m >= n,m表示显示m位整数,n表示最多n位位于小数点后面。 |
double(m, n) | 8 | 双精度浮点数值。代码中允许近似值存在,一律使用float、double类型。 |
decimal(m, n) | 8 | 对于货币、金额等不允许四舍五入,一律用decimal |
2. 字符串类型
-
char(n)
char(n)占n字节,1<=n<=255,如果字段值都接近某一固定长度max(length(column_name)) < n 且该字段更新比较频繁,建议使用char(n)。
例如:order_sn,uuid固定长度的字段等等。 -
varchar(m)
varchar(m)占L字节,1 <= L <= 65 535,其中最大能存储n个字符(utf8表吗),1 <= n <= 21 845,如果字符串列的最大长度比平均长度大很多且更新不频繁,建议使用varchar(m)。
例如:账号、名称、标题、内容等。
comment_content、content、description、title、news等等。
3. text和blob类型
test
和blob
都是未来存储较大数据而设计的字符串类型,分别采用字符和二进制方式存储。下面主要介绍几种不同类型能存储多大字节数。
类型 | 字节 | 说明 |
---|---|---|
tinyblob | 255 | L<2^8 |
tinytext | 255 | L<2^8 |
blob | 64K | L<2^16 |
text | 64K | L<2^16 |
mediumblob | 16M | L<2^24 |
mediumtext | 16M | L<2^24 |
longblob | 4GB | L<2^32 |
longtext | 4GB | L<2^32 |
需要注意blob类型存储是二进制数据,没有排序规则和字符集,而text类型有字符集和排序规则。
4. datetime
和timestamp
类型 | 字节 | 说明 |
---|---|---|
datetime | 8 | 范围为1000-01-01 00:00:00 ~ 9999-12-31 23:59:59(和时区无关) |
timestamp | 4 | 1970-01-01 08:00:01 到 2038-01-19 11:14:07(和时区有关)。如果在多个失去存储或访问数据,会出现不同的结果。 |
如果没有特殊需求,默认时间类型用timestamp
类型。
5. float
,double
和decimal
类型 | 字节 | 说明 |
---|---|---|
float | 4 | 单精度浮点数值(不精确) |
double | 8 | 双精度浮点数值(不精确) |
decimal | decimail(M,D)占M+2个字节 | MySQL在内部把DECIMAL数据类型存储为字符串,更精确地保留它们的值 |
6. tinyint
使用tinyint
来代替 enum
和boolean
,enum
类型在需要修改或增加枚举值时,需要在线DDL,成本较高;enum
列值如果含有数字类型,可能会引起默认值混淆;tinyint
使用1个字节,一般用于status,type,flag
的列
2.6 默认情况
1. 主键
所有的表必须包含主键,默认需要设置成自增主键(表名_id),且开启AUTO_INCREMENT
,主键常用为bigint
(18)/bigint
(20)/int
(11)/int
(10)。
2. 外键
即使两个表的字段有明确的外键参考关系,也不使用FOREIGN KEY
,因为新纪录会去主键表做校验,影响性能。外键通过程序事务操作进行处理。
3. 默认值
每个字段必须不为空(not null),同时有默认值(默认值可以选择空字符’'或0等),当字段类型为text/blob类型,不设置默认值。