第438集MySQL40条军规
MySQL 40条军规
1. 军规概述
1.1 什么是MySQL军规
MySQL 40条军规是经过大量实践总结出来的MySQL数据库开发、运维、管理的最佳实践规范。这些规范涵盖了DBA操作、行为规范、基本规范、库表设计、字段设计、索引设计、SQL设计等各个方面。
军规的核心价值:
- 避免常见错误:防止因不规范操作导致的问题
- 提高开发效率:统一的规范提高团队协作效率
- 保障系统稳定:规范的操作保障系统稳定性
- 提升系统性能:合理的设计提升系统性能
1.2 军规分类
MySQL 40条军规分为以下7个类别:
- DBA操作规范(1-7条):DBA日常操作规范
- 行为规范(8-12条):开发和运维行为规范
- 基本规范(13-20条):数据库基本使用规范
- 库表设计规范(21-22条):库表设计规范
- 字段设计规范(23-27条):字段设计规范
- 索引规范(28-34条):索引设计和使用规范
- SQL设计规范(35-40条):SQL语句编写规范
2. DBA操作规范
2.1 军规1:业务数据修改审批流程
规范内容:
涉及业务上的修改/删除数据,在得到业务方、CTO的邮件批准后方可执行,执行前提前做好备份,必要时可逆。
重要性
原因:
- 数据修改/删除是不可逆操作
- 需要多方确认,避免误操作
- 备份是数据安全的最后防线
执行流程
1 | 1. 业务方提出需求 |
备份要求
1 | # 执行前备份 |
可逆操作
示例:删除数据前先备份,删除后可以恢复
1 | -- 1. 备份数据 |
2.2 军规2:工单系统管理
规范内容:
所有上线需求必须走工单系统,口头通知视为无效。
重要性
原因:
- 工单系统有完整的记录
- 可以追溯和审计
- 避免口头通知的误解
工单内容要求
工单必须包含:
- 需求描述
- 影响范围
- 执行时间
- 回滚方案
- 审批流程
工单流程
1 | 1. 提交工单 |
2.3 军规3:大表结构变更规范
规范内容:
在对大表做表结构变更时,如修改字段属性会造成锁表,并会造成从库延迟,从而影响线上业务,必须在凌晨0:00后业务低峰期执行,另统一用工具pt-online-schema-change避免锁表且降低延迟执行时间。
问题分析
传统ALTER TABLE的问题:
- 会锁表,影响业务
- 从库延迟增加
- 执行时间长
解决方案
使用pt-online-schema-change工具:
1 | # pt-online-schema-change使用范例 |
参数说明:
| 参数 | 说明 |
|---|---|
--alter |
要执行的ALTER语句 |
--no-check-replication-filters |
不检查复制过滤器 |
--recursion-method |
复制检测方法 |
D=test,t=t1 |
数据库和表名 |
--execute |
执行操作 |
优势:
- 不锁表,业务不中断
- 降低从库延迟
- 可以随时中断
MongoDB索引创建
对于MongoDB创建索引要在后台创建,避免锁表:
1 | // MongoDB后台创建索引 |
说明:
background:1:后台创建索引- 不阻塞其他操作
- 适合生产环境
2.4 军规4:MHA高可用架构
规范内容:
所有线上业务库均必须搭建MHA高可用架构,避免单点问题。
MHA架构
MHA(Master High Availability)是MySQL高可用解决方案。
架构特点:
- 自动故障检测
- 自动主从切换
- 数据一致性保证
- 快速故障恢复
架构要求
所有线上业务库必须:
- 搭建主从复制
- 配置MHA
- 定期演练故障切换
- 监控主从状态
2.5 军规5:权限管理规范
规范内容:
给业务方开权限时,密码要用MD5加密,至少16位。权限如没有特殊要求,均为select查询权限,并做库表级限制。
密码要求
密码规范:
- 长度:至少16位
- 复杂度:包含大小写字母、数字、特殊字符
- 加密:使用MD5加密存储
示例:
1 | -- 创建用户,密码至少16位 |
权限原则
最小权限原则:
1 | -- 推荐:只给SELECT权限 |
2.6 军规6:删除默认空密码账号
规范内容:
删除默认空密码账号。
安全风险
空密码账号的风险:
- 任何人都可以连接
- 安全漏洞
- 不符合安全规范
执行操作
1 | -- 删除空密码账号 |
2.7 军规7:审计日志功能
规范内容:
汇总库开启Audit审计日志功能,出现问题时方可追溯。
审计日志重要性
作用:
- 记录所有数据库操作
- 问题追溯
- 安全审计
- 合规要求
开启审计日志
MySQL Enterprise Audit(商业版):
1 | -- 安装审计插件 |
开源方案:
- 使用binlog记录
- 使用触发器记录
- 使用中间件记录
3. 行为规范
3.1 军规8:禁止多业务数据库混用
规范内容:
禁止一个MySQL实例存放多个业务数据库,会造成业务耦合性过高,一旦出现问题会殃及池鱼,增加了定位故障问题的难度。通常采用多实例解决,一个实例一个业务库,互不干扰。
问题分析
多业务数据库混用的问题:
- 业务耦合性高
- 故障影响范围大
- 难以定位问题
- 资源竞争
解决方案
多实例部署:
1 | # 实例1:用户库 |
优势:
- 业务隔离
- 独立配置
- 独立监控
- 便于管理
3.2 军规9:禁止主库执行统计查询
规范内容:
禁止在主库上执行后台管理和统计类的功能查询,这种复杂类的SQL会造成CPU的升高,进而会影响业务。
问题分析
主库执行统计查询的问题:
- 消耗CPU资源
- 影响业务性能
- 可能导致主从延迟
解决方案
使用从库执行统计查询:
1 | -- 不推荐:在主库执行 |
或者使用专门的统计库:
- 从库专门用于统计
- 不影响主库性能
- 不影响业务
3.3 军规10:批量清洗数据规范
规范内容:
批量清洗数据,需要开发和DBA共同进行审查,应避开业务高峰期时段执行,并在执行过程中观察服务状态。
执行流程
1 | 1. 开发和DBA共同审查 |
执行时间
推荐时间:
- 凌晨0:00-6:00
- 业务低峰期
- 避开促销活动
监控要求
执行过程中监控:
- CPU使用率
- 内存使用率
- 磁盘IO
- 数据库连接数
- 慢查询数量
3.4 军规11:促销活动提前沟通
规范内容:
促销活动等应提前与DBA当面沟通,进行流量评估,比如提前一周增加机器内存或扩展架构,防止DB出现性能瓶颈。
沟通内容
提前沟通事项:
- 活动时间
- 预期流量
- 业务场景
- 性能要求
准备工作
提前一周准备:
- 增加机器内存
- 扩展架构
- 优化SQL
- 增加从库
- 压力测试
流量评估
评估指标:
- QPS(每秒查询数)
- TPS(每秒事务数)
- 并发连接数
- 数据增长量
3.5 军规12:禁止线上压力测试
规范内容:
禁止在线上做数据库压力测试。
风险分析
线上压力测试的风险:
- 影响正常业务
- 可能导致服务不可用
- 数据安全风险
- 违反规范
解决方案
使用测试环境:
- 搭建与生产环境相同的测试环境
- 在测试环境进行压力测试
- 验证性能后再上线
4. 基本规范
4.1 军规13:禁止存储明文密码
规范内容:
禁止在数据库中存储明文密码。
安全要求
密码存储规范:
- 使用加密算法(MD5、SHA256、bcrypt)
- 加盐(Salt)处理
- 定期更换密码
示例:
1 | -- 不推荐:明文密码 |
4.2 军规14:使用InnoDB存储引擎
规范内容:
使用InnoDB存储引擎。支持事务,行级锁,更好的恢复性,高并发下性能更好。InnoDB表避免使用COUNT(*)操作,因内部没有计数器,需要一行一行累加计算,计数统计实时要求较强可以使用memcache或者Redis。
InnoDB优势
InnoDB特性:
- 事务支持:ACID特性
- 行级锁:并发性能好
- 崩溃恢复:恢复能力强
- 外键支持:数据完整性
- 高并发:性能优秀
COUNT(*)优化
问题:InnoDB的COUNT(*)需要全表扫描
解决方案:
1 | -- 不推荐:COUNT(*) |
4.3 军规15:统一使用UTF8字符集
规范内容:
表字符集统一使用UTF8。不会产生乱码风险。
字符集选择
推荐UTF8MB4:
1 | -- 创建数据库 |
UTF8 vs UTF8MB4:
- UTF8:3字节,不支持emoji
- UTF8MB4:4字节,支持emoji和所有Unicode字符
推荐使用UTF8MB4。
4.4 军规16:添加中文注释
规范内容:
所有表和字段都需要添加中文注释。方便他人、方便自己。
注释规范
1 | -- 表注释 |
注释的重要性:
- 便于理解业务
- 降低维护成本
- 提高开发效率
4.5 军规17:不存储大文件
规范内容:
不在数据库中存储图片、文件等大数据。图片、文件更适合于GFS分布式文件系统,数据库里存放超链接即可。
问题分析
存储大文件的问题:
- 数据库体积增大
- 查询性能下降
- 备份恢复困难
- 不符合数据库设计原则
解决方案
使用文件系统存储:
1 | -- 不推荐:存储文件内容 |
推荐方案:
- GFS:Google文件系统
- HDFS:Hadoop分布式文件系统
- OSS:对象存储服务
- CDN:内容分发网络
4.6 军规18:避免使用存储过程等
规范内容:
避免使用存储过程、视图、触发器、事件。MySQL是OLTP应用,最擅长简单的增、删、改、查操作,但对逻辑计算分析类的应用,并不适合,所以这部分的需求最好通过程序上实现。
原因分析
避免使用的原因:
- 可移植性差:不同数据库语法不同
- 调试困难:难以调试和测试
- 维护成本高:业务逻辑分散
- 性能考虑:可能影响性能
推荐方案
在应用层实现:
- 业务逻辑在应用层
- 数据库只负责数据存储
- 便于维护和扩展
4.7 军规19:避免使用外键
规范内容:
避免使用外键,外键用来保护参照完整性,可在业务端实现。外键会导致父表和子表之间耦合,十分影响SQL性能,出现过多的锁等待,甚至会造成死锁。
问题分析
外键的问题:
- 性能影响:额外的检查开销
- 锁等待:可能导致死锁
- 耦合度高:表之间强耦合
- 维护困难:删除数据需要先删除关联数据
解决方案
在业务层实现:
1 | -- 不推荐:使用外键 |
4.8 军规20:日志表使用MongoDB
规范内容:
对事务一致性要求不高的业务,如日志表等,优先选择存入MongoDB。其自身支持的sharding分片功能,增强了横向扩展的能力,开发不用过多调整业务代码。
适用场景
MongoDB适用场景:
- 日志表
- 统计表
- 非关键业务数据
- 大数据量场景
优势
MongoDB优势:
- 支持sharding分片
- 横向扩展能力强
- 写入性能好
- 灵活的数据模型
5. 库表设计规范
5.1 军规21:表必须有主键
规范内容:
表必须有主键,例如自增主键。这样可以保证数据行是按照顺序写入,对于SAS传统机械式硬盘写入性能更好,根据主键做关联查询的性能也会更好,并且还方便了数据仓库抽取数据。从性能的角度来说,使用UUID作为主键是个最不好的方法,它会使插入变得随机。
主键的重要性
主键的作用:
- 唯一标识记录
- 提高查询性能
- 优化写入性能
- 便于数据仓库抽取
主键选择
推荐:自增主键:
1 | -- 推荐:自增主键 |
优势:
- 顺序写入,性能好
- 索引效率高
- 关联查询快
不推荐:UUID主键:
1 | -- 不推荐:UUID主键 |
问题:
- 随机写入,性能差
- 索引效率低
- 占用空间大
5.2 军规22:禁止使用分区表
规范内容:
禁止使用分区表。分区表的好处是对于开发来说,不用修改代码,通过后端DB的设置,比如对于时间字段做拆分,就可以轻松实现表的拆分。但这里面涉及一个问题,查询的字段必须是分区键,否则会遍历所有的分区表,并不会带来性能上的提升。此外,分区表在物理结构上仍旧是一张表,此时我们更改表结构,一样不会带来性能上的提升。所以应采用切表的形式做拆分,如程序上需要对历史数据做查询,可通过union all的方式关联查询。
分区表的问题
分区表的限制:
- 查询必须包含分区键
- 否则遍历所有分区
- 表结构变更性能差
- 物理上仍是一张表
解决方案
使用切表方式:
1 | -- 不推荐:分区表 |
优势:
- 查询性能好
- 表结构变更快
- 便于管理
- 可以独立备份
6. 字段设计规范
6.1 军规23:使用DECIMAL代替FLOAT
规范内容:
用DECIMAL代替FLOAT和DOUBLE存储精确浮点数。浮点数的缺点是会引起精度问题。
精度问题演示
1 | -- 创建测试表 |
问题:FLOAT类型精度丢失,999998.02变成了999998.00
解决方案
使用DECIMAL类型:
1 | -- 推荐:使用DECIMAL |
适用场景:
- 货币金额
- 精确计算
- 财务数据
6.2 军规24:使用TINYINT代替ENUM
规范内容:
使用TINYINT来代替ENUM类型。采用enum枚举类型,会存在扩展的问题,例如用户在线状态,如果此时增加了:5表示请勿打扰、6表示开会中、7表示隐身对好友可见,那么增加新的ENUM值要做DDL修改表结构操作了。
ENUM的问题
ENUM类型的限制:
- 扩展需要DDL操作
- 修改表结构影响业务
- 不够灵活
解决方案
使用TINYINT:
1 | -- 不推荐:使用ENUM |
优势:
- 扩展不需要DDL
- 更灵活
- 性能相同
6.3 军规25:字段长度按需分配
规范内容:
字段长度尽量按实际需要进行分配,不要随意分配一个很大的容量。选择字段的一般原则是保小不保大,能用占用字节少的字段就不用大字段。
字段选择原则
保小不保大原则:
1 | -- 不推荐:随意使用INT |
数据类型对比
| 类型 | 字节 | 范围 | 适用场景 |
|---|---|---|---|
| TINYINT | 1 | -128~127 | 年龄、状态 |
| SMALLINT | 2 | -32768~32767 | 年份、数量 |
| MEDIUMINT | 3 | -8388608~8388607 | ID、计数 |
| INT | 4 | -2147483648~2147483647 | 主键、ID |
| BIGINT | 8 | 很大 | 大ID、时间戳 |
INT长度说明
重要:INT(10)和INT(1)没有区别,10和1仅是显示宽度。
1 | -- 创建测试表 |
说明:只有在设置了ZEROFILL时,显示宽度才有意义。
6.4 军规26:NOT NULL要提供默认值
规范内容:
字段定义为NOT NULL要提供默认值。从应用层角度来看,可以减少程序判断代码,比如你要查询一条记录,如果没默认值,你是不是得先判断该字段对应变量是否被设置,如果没有,你得通过java把该变量置为’’或者0,如果设了默认值,判断条件可直接略过。NULL值很难进行查询优化,它会使索引统计更加复杂,还需要MySQL内部进行特殊处理。
NULL值的问题
NULL值的影响:
- 查询优化困难
- 索引统计复杂
- 需要特殊处理
- 应用层判断复杂
解决方案
使用NOT NULL和默认值:
1 | -- 不推荐:允许NULL |
优势:
- 减少应用层判断
- 提高查询性能
- 简化索引统计
6.5 军规27:尽可能不使用TEXT/BLOB
规范内容:
尽可能不使用TEXT、BLOB类型。增加存储空间的占用,读取速度慢。
TEXT/BLOB的问题
问题:
- 存储空间大
- 读取速度慢
- 影响SELECT *性能
- 备份恢复慢
解决方案
拆分到子表:
1 | -- 不推荐:TEXT和主表在一起 |
优势:
- 主表查询快
- 按需查询内容
- 便于管理
7. 索引规范
7.1 军规28:索引不是越多越好
规范内容:
索引不是越多越好,按实际需要进行创建。索引是一把双刃剑,它可以提高查询效率但也会降低插入和更新的速度并占用磁盘空间。
索引的代价
索引的缺点:
- 降低写入速度
- 占用磁盘空间
- 维护成本高
索引选择原则
创建索引的原则:
- 经常用于WHERE条件
- 经常用于JOIN
- 经常用于ORDER BY
- 高选择性字段
不创建索引的情况:
- 很少查询的字段
- 低选择性字段
- 频繁更新的字段
7.2 军规29:查询字段必须创建索引
规范内容:
查询的字段必须创建索引。如:1、SELECT、UPDATE、DELETE语句的WHERE条件列;2、多表JOIN的字段。
必须创建索引的场景
WHERE条件列:
1 | -- 必须为id创建索引 |
JOIN字段:
1 | -- 必须为关联字段创建索引 |
7.3 军规30:不在索引列进行运算
规范内容:
不在索引列进行数学运算和函数运算。无法使用索引,导致全表扫描。
问题示例
1 | -- 不推荐:使用函数 |
常见错误
数学运算:
1 | -- 不推荐 |
函数运算:
1 | -- 不推荐 |
7.4 军规31:不在低基数列建立索引
规范内容:
不在低基数列上建立索引,例如’性别’。有时候,进行全表浏览要比必须读取索引和数据表更快,尤其是当索引包含的是平均分布的数据集是更是如此。
低基数列示例
低基数列:
- 性别:只有2个值(男、女)
- 状态:只有几个值
- 布尔值:只有2个值
解决方案
使用复合索引:
1 | -- 不推荐:单独为性别创建索引 |
7.5 军规32:不使用%前导查询
规范内容:
不使用%前导的查询,如like ‘%xxx’。无法使用索引,导致全表扫描。
问题分析
1 | -- 不推荐:%前导 |
解决方案
如果必须使用%前导:
- 使用全文索引(Elasticsearch)
- 使用搜索引擎
- 在应用层处理
7.6 军规33:不使用反向查询
规范内容:
不使用反向查询,如 not in / not like。无法使用索引,导致全表扫描。
问题示例
1 | -- 不推荐:NOT IN |
7.7 军规34:避免冗余或重复索引
规范内容:
避免冗余或重复索引。联合索引IX_a_b_c(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c),那么索引 (a) 、(a,b) 就是多余的。
索引冗余示例
1 | -- 不推荐:冗余索引 |
检查重复索引
1 | # 使用pt-duplicate-key-checker检查 |
8. SQL设计规范
8.1 军规35:不使用SELECT *
规范内容:
不使用SELECT *,只获取必要的字段。消耗CPU和IO、消耗网络带宽;无法使用覆盖索引。
问题分析
**SELECT *的问题**:
- 读取不需要的字段
- 消耗CPU和IO
- 消耗网络带宽
- 无法使用覆盖索引
解决方案
1 | -- 不推荐 |
覆盖索引优势:
1 | -- 如果索引包含所有需要的字段,可以直接从索引获取数据 |
8.2 军规36:用IN替换OR
规范内容:
用IN来替换OR。
性能对比
1 | -- 不推荐:使用OR |
优势:
- IN可以使用索引
- OR可能无法使用索引
- IN性能更好
8.3 军规37:避免数据类型不一致
规范内容:
避免数据类型不一致。
问题示例
1 | -- 不推荐:类型不一致 |
影响:
- 类型转换消耗CPU
- 可能无法使用索引
- 性能下降
8.4 军规38:减少数据库交互次数
规范内容:
减少与数据库的交互次数。
批量操作
INSERT优化:
1 | -- 不推荐:多次INSERT |
UPDATE优化:
1 | -- 推荐:批量UPDATE |
ALTER优化:
1 | -- 推荐:一次ALTER多个操作 |
8.5 军规39:拒绝大SQL,拆分成小SQL
规范内容:
拒绝大SQL,拆分成小SQL。
问题分析
大SQL的问题:
- 执行时间长
- 锁表时间长
- 难以优化
- 影响其他查询
解决方案
1 | -- 不推荐:大SQL |
优势:
- 执行时间短
- 便于优化
- 减少锁表时间
- 提高并发性能
8.6 军规40:禁止使用ORDER BY RAND()
规范内容:
禁止使用order by rand()。
问题分析
ORDER BY RAND()的问题:
- 性能极差
- 需要全表扫描
- 无法使用索引
- 数据量大时几乎不可用
解决方案
1 | -- 不推荐:ORDER BY RAND() |
9. 军规总结
9.1 军规分类统计
| 类别 | 数量 | 军规编号 |
|---|---|---|
| DBA操作规范 | 7条 | 1-7 |
| 行为规范 | 5条 | 8-12 |
| 基本规范 | 8条 | 13-20 |
| 库表设计规范 | 2条 | 21-22 |
| 字段设计规范 | 5条 | 23-27 |
| 索引规范 | 7条 | 28-34 |
| SQL设计规范 | 6条 | 35-40 |
9.2 核心原则
- 安全第一:所有操作都要有备份和审批
- 性能优先:设计时考虑性能影响
- 规范统一:团队统一规范,提高效率
- 持续优化:根据实际情况持续优化
9.3 架构师建议
- 建立规范:制定团队开发规范
- 代码审查:定期进行代码审查
- 培训教育:定期培训开发人员
- 工具支持:使用工具检查规范
- 持续改进:根据实践持续改进规范
9.4 检查清单
- 所有操作是否有审批和备份
- 是否使用工单系统
- 大表变更是否使用pt工具
- 是否搭建MHA高可用
- 用户权限是否最小化
- 是否使用InnoDB引擎
- 表是否有主键
- 字段是否使用合适的数据类型
- 索引是否合理
- SQL是否优化
相关文章:


