你知道什么是 MySQL Online DDL 吗?
前言
MySQL 在进行 DDL 操作时,可能会产生表锁导致阻塞,影响用户的 DML 操作,而 Online DDL 指的是在 DDL 期间,允许用户进行 DML 操作。本文将详细讲解 MySQL 各版本的 Online DDL。关于什么是 DDL 和 DML 操作,详细介绍见 MySQL 操作命令总结。
1. 什么是 Online DDL
Online DDL 功能从 5.6 版本开始正式引入,可以支持 DDL 操作期间,允许 DML 操作同时进行,尽量避免 DDL 过程中对业务 SQL 产生的阻塞。8.0 版本对 DDL 的实现重新进行了设计,支持了原子特性。
那么为什么要引入 Online DDL?MySQL 5.5 版本及之前,在进行 DDL 操作的时候,整个表都会被阻塞,当用户或业务对表进行 DML 操作时就会被阻塞。如果在生产环境出现这种情况,导致整个服务的可用性降低,影响用户操作,这通常是不能被接受的。
引入 Online DDL 可以让 MySQL 在 DDL 操作期间,允许 DML 操作同时进行,减少表锁导致的业务阻塞,提高了服务的可用性、降低了业务风险。
Online DDL 常用的几种操作:索引相关操作、主键相关操作、列相关操作、表相关操作。
2. Online DDL 算法
DDL 操作期间,无论哪种算法都会经历三个阶段:
- 准备阶段(Prepare)
- 执行阶段(DDL 语句)
- 提交阶段(Commit)
2.1. Copy 算法
Copy 方式下 DDL 操作会生成临时新表,将原表数据逐行拷贝到新表中,在此期间会阻塞 DML,但允许查询。拷贝完成后的那一时刻原表禁止读写操作,因为在清理旧表结构和表定义缓存。
之后会在临时表上执行 DDL 语句,操作完成后原表会被删除,新表被重命名为原表名。该方式适用于需要做大量结构修改且表数据较少的情况。
COPY 方式下DDL 操作肯定不是 Online DDL。
执行流程如下图:
2.2. INPLACE 算法
INPLACE 方式下DDL 操作不会新建临时表,也无需拷贝全表数据到新表,优点是不需要额外的存储空间,但可能会产生较大的锁、阻塞和性能开销。分为两类:
rebuild
:需要重建表,如,添加/删除主键。no-rebuild
:不需要重建表,如,修改列名、修改自增值等)。
对于rebuild
方式,DDL 期间会缓存 DML,待完成之后,再进行 DML 操作。这种情况下,在 DDL 的初始准备和最后结束两个阶段时通常需要加 MDL 排他写锁,除此外,DDL 期间不会阻塞 DML。
即使使用 INPLACE 算法,虽然不会创建新表,但过程中可能会涉及到创建临时的数据文件进行辅助修改,所以都会需要额外的数据空间。
2.3. INSTANT 算法
INSTANT 方式是 8.0.12 引入的,只需修改数据字典中的元数据,无需拷贝数据也无需重建整表,同样,也无需加MDL 排他写锁,原表数据也不受影响。整个DDL过程几乎是瞬间完成的,也不会阻塞DML。
3. 各版本 Online DDL 总结
本文数据全部来自 MySQL 官方文档,由于 5.6 版本不在维护,本文仅整理目前常用的 5.7 和 8.0 版本。
3.1. MySQL 5.7
3.2. MySQL 8.0
3.3. 关于扩展 varchar 长度
根据官方文档描述,扩展 varchar 长度时使用的算法与该列所占用的字节数(不是字符)有关。具体逻辑如下:
- varchar 长度在 0-255 字节时,需要用 1 个字节编码值;
- varchar 长度在 256 以上字节时,需要用 2 个字节编码值;
- 如果扩展前后的大小均在 0-255 字节范围内或均大于 256 字节,则可以使用 INPLACE 算法,否则只能通过 COPY 算法进行 DDL;
- 如果进行减少 varchar 长度,则只能使用 COPY 算法。
3.4. Online DDL 会不会锁表
很多 MySQL 用户经常在表无法正常的进行 DML 时就觉得是锁表了,这种说法其实过于宽泛,实际上能够影响 DML 操作的锁主要有:
- 元数据(MDL)锁
- 表锁
- 行锁
- 间隙锁(GAP)锁
其中只有表锁和元数据锁可能进行锁表,关于锁的内容,详情见另一篇文章 MySQL 锁。
一个 DDL 的基本过程是这样的:
- 准备阶段,需要拿到对应表的 MDL 排他写锁,然后进行一系列的准备工作;
- 执行阶段,将 MDL 排他写锁降级为 MDL 共享读锁,进行真正的 DDL 操作;
- 提交阶段,将 MDL 共享读锁升级为 MDL 排他写锁,完成 DDL 操作,释放 MDL 锁;
所以在真正执行 DDL 操作期间,确实是不会锁表的,但是如果在准备阶段和提交阶段为 MDL 排他写锁 期间是进行锁表的。
3.5. 版本总结
通过 3.1 和 3.2 的表格的整理可以得到一下几个结论:
1. 即使使用 INPLACE 算法,执行的 DDL 也不一定是 Online DDL。
2. INSTANT 方式 是 MySQL 8.0 引入的新功能,当前支持的范围较小,仅包括:
- 修改二级索引类型
- 新增/删除/重命名列
- 修改列默认值
- 修改列 ENUM 值
- 重命名表
3. 我们常说的 Online DDL,其实是从 DML 操作的角度描述的,如果 DDL 操作不阻塞 DML 操作,那么这个 DDL 就是 Online 的。当前非 Online DDL 其实已经比较少了,主要有:
- 新增全文索引
- 新增空间索引
- 删除主键
- 修改列数据类型
- 指定表字符集
- 修改表字符集
4. 在执行 DDL 操作时,用户可以通过ALGORITHM=COPY
主动指定算法,若未指定,则优先选择 INPLACE,若不支持 INPLACE 则选择 COPY,当前不支持 INPLACE 的操作主要有:
- 删除主键
- 修改列数据类型
- 修改表字符集
4. 第三方工具实现 Online DDL
除了支持 INSTANT 算法的 DDL 操作,其余的建议采用gh-osc/pt-osc
工具进行 DDL 操作。
4.1. gh-ost
推荐文章:MySQL 最佳实践:gh-ost 工具使用详解-腾讯云开发者社区-腾讯云
4.2. pt-osc
推荐文章:PT-OSC在线DDL变更工具使用攻略-腾讯云开发者社区-腾讯云