mysql 5.6 及以后版本(尤其是 innodb 存储引擎)引入的一项极其重要的功能,它允许数据库管理员在执行 alter table
操作时,最大程度地减少对表锁定和应用程序可用性的影响。
核心目标: 在 ddl 操作进行时,允许对表进行并发的读取(select) 和写入(insert, update, delete) 操作。
一、online ddl 是什么?
online ddl 是 mysql 5.6 版本引入,并在后续版本中不断增强的一项功能。它允许你在执行数据定义语言(ddl)操作时(如 alter table
),尽可能地减少对表的锁定时问,使得:
- 写操作(dml):在 ddl 操作进行的同时,应用程序依然可以对表执行
insert
,update
,delete
等操作,最大程度保证业务的连续性。 - 读操作:
select
查询通常可以正常进行,不受影响。
这与早期的 copy table 机制形成鲜明对比,早期方式需要全程锁表,直到操作完成,对于大表来说意味着长时间的停机。
二、online ddl 的三种主要算法
mysql 在执行 ddl 时,根据操作类型的不同,底层主要采用三种算法。理解这些算法是理解 online ddl 的关键。
2.1copy(复制法)
过程:
- 创建一个与原始表结构相同的临时表(
.frm
,.ibd
等文件)。 - 在新的临时表上执行 ddl 操作。
- 将原始表的数据逐行复制到临时表中。
- 在此期间,对原始表的写操作会被阻塞(通常只在数据拷贝的最后阶段有短暂锁表)。
- 数据复制完成后,用新的临时表替换原始表,并删除旧的表。
特点:
- 需要两倍的存储空间。
- 过程中大部分时间会阻塞写操作,影响业务。
- 是 mysql 5.5 及之前版本的主要方式。
2.2 inplace (原地法)
过程:
无需创建临时表文件,直接在原始表的存储文件(如 innodb 的 .ibd
文件)上进行操作。
通常分为两个阶段:
- 准备阶段(prepare):创建新的.frm文件,准备数据字典更改。可能需要短暂的排他锁(x锁)。
- 执行阶段(execute):应用更改到存储引擎,这通常是操作中最耗时的部分。在此阶段,允许并发的dml操作。
特点:
- 所需磁盘空间远少于 copy 算法(通常只需要日志文件的空间)。
- 允许在执行阶段进行并发 dml,大大减少了锁表时间。
2.3instant (即刻法,mysql 8.0+)
过程:
- 操作只修改数据字典(元数据),而不触及表中的实际数据或索引。
- 例如,添加一个可为
null
且有默认值的列,只需要在数据字典中记录一下“这个表有这个列,默认值是什么”,而不需要重建表或复制数据。
特点:
- 速度极快,通常能在毫秒级完成。
- 完全不阻塞任何 dml 操作,是真正的“online”。
- 对存储空间没有额外要求。
三、online ddl 的锁机制
即使是 inplace 算法,也并非全程无锁。online ddl 涉及两种主要的锁:
- shared锁(读锁):在 ddl 的准备阶段,可能会短暂地获取。允许其他会话读,但阻塞写。
- exclusive锁(写锁/排他锁):在 ddl 的开始(准备阶段)和结束(提交阶段)可能会短暂地获取。此时会阻塞所有其他的读和写操作。
关键点:online ddl 的“online”体现在其耗时的数据拷贝/重建阶段(execute阶段)是不锁表的,而只在元数据变更的瞬间需要短暂的排他锁。这个瞬间通常非常短,可以忽略不计。
四 关键区别
特性 | copy | inplace | instant |
---|---|---|---|
核心方式 | 重建整个表 | 原地修改,避免重建整个表 | 仅修改元数据 |
锁表时间 | 长 (全程锁或长写锁) | 短 (准备/提交锁) | 极短 (毫秒级元数据锁) |
执行阶段 | 不允许读写 | 允许并发读写 | 允许并发读写 |
空间占用 | 双倍表空间 | 额外日志/临时文件空间 | 几乎无额外空间 |
速度 | 慢 | 中等 (取决于操作复杂度) | 极快 (毫秒级) |
并发影响 | 高 (停机) | 低 (短暂阻塞写) | 极低 (几乎无感知) |
主要优势 | 兼容性 | 平衡性能和并发 | 瞬时完成,零感知 |
典型操作 | 部分无法 inplace 的操作 (如删除主键) | 添加/删除索引、修改列属性等 | 添加/删除列 (有条件)、改默认值 |
4.1 生动的比喻:给飞行中的飞机换引擎
想象一下,你要给一架正在飞行的飞机更换引擎(这相当于对数据库表做 alter table
)。
copy 算法:让所有乘客下飞机(阻塞 dml),把飞机拖进机库,拆下旧引擎,换上新引擎,最后再让乘客登机。在此期间,飞机完全停运。
inplace 算法:
- 准备阶段 (prepare):工程师们做好所有准备工作:新引擎运到机场,所有工具就位。这需要飞机短暂地保持静止(短暂的排他锁)。
- 执行阶段 (execute):飞机保持飞行状态(允许并发 dml)。工程师们挂在机翼上,开始拆卸旧引擎,同时安装新引擎。乘客们(dml 操作)仍然可以在机舱内正常走动、点餐(
insert
,update
,delete
)。 - 提交阶段:新引擎安装完毕,最后进行一个极其快速的切换和检查,确保新引擎完全接管工作。这又需要飞机瞬间的静止(短暂的排他锁)。
4.2 如何指定和查看算法
指定算法: 在 alter table
语句中使用 algorithm
子句。
alter table your_table add column new_col int, algorithm=instant; -- 尝试强制使用 instant alter table your_table add index idx_name (col_name), algorithm=inplace, lock=none; -- 尝试强制 inplace 且无锁
algorithm=default
:让 mysql 选择它认为最高效的可用算法。algorithm=copy | inplace | instant
:强制使用特定算法。如果该算法不支持此操作,语句会报错。
指定锁策略: 使用 lock
子句。
alter table ... lock=none; -- 尽可能允许并发读写 (最高并发) alter table ... lock=shared; -- 允许读,阻塞写 alter table ... lock=exclusive; -- 阻塞读写 (传统方式) alter table ... lock=default; -- 让 mysql 选择最小必要的锁策略
指定的 lock
级别必须兼容于操作本身支持的级别。例如,一个操作在 inplace 执行阶段允许 lock=none
,但你强制指定 lock=exclusive
是允许的(虽然不推荐)。反之,如果操作本身在某个阶段必须短暂加 exclusive
锁,你指定 lock=none
会导致语句失败。
查看算法和锁: 执行 alter table
前,使用 alter table ... algorithm=inplace, lock=none
并加上 no_write_to_binlog
和 commit
子句通常不会真正执行,mysql 会检查并报告它将使用的算法和锁。更好的方法是查询 information_schema.innodb_tables
或使用 show create table
观察进度(对于长时间操作),或者直接执行后观察输出信息(很多客户端会显示使用的算法)。最准确的是查看官方文档对具体操作的支持矩阵。
4.3 重要注意事项
- 并非所有 ddl 都是 online 的: 即使使用 inplace 算法,部分操作在准备或提交阶段也需要短暂的排他锁 (
exclusive
)。一些操作(如修改主键、修改某些列的数据类型、更改表字符集等)可能仍然需要 copy 算法或更长时间的锁。务必查阅官方文档对应版本的 online ddl 支持矩阵。 - 空间与性能: inplace 操作虽然避免了重建整个表,但可能涉及大量的数据重组、日志记录、排序操作,仍然会消耗大量 i/o 和 cpu 资源,可能影响系统性能。instant 操作在这方面开销最小。
- 复制: online ddl 在 mysql 复制环境(主从)中的行为也需要考虑。通常在主库上执行的 online ddl,其效果也会在从库上以类似的方式应用(可能也是 online 的,取决于从库版本和设置)。
- 元数据锁 (mdl): 即使算法本身允许并发 dml,长时间的 ddl 操作也可能因为持有 mdl 而阻塞后续需要获取冲突 mdl 的其他 ddl 或某些事务。
lock=none
的目标就是最小化 mdl 冲突。 - instant 的限制: instant 算法虽然强大,但有诸多限制(列的位置、数据类型、索引类型、表格式等),且限制随版本更新而变化。使用前务必确认操作是否支持
algorithm=instant
。 - 版本差异: online ddl 的支持程度和具体行为在不同 mysql 版本(5.6, 5.7, 8.0)和 innodb 版本中有显著差异。强烈建议参考对应版本的官方文档。
三、总结
mysql 的 online ddl 通过 copy, inplace, instant 三种算法,极大地提升了 ddl 操作的并发性和可用性。尤其是 instant 算法(mysql 8.0+)对于支持的列操作实现了近乎瞬时的变更,对在线业务影响最小。inplace 算法则是大多数索引和列操作的主力,在执行阶段允许并发读写。copy 算法作为最后的选择,应尽量避免。
最佳实践:
- 优先使用 mysql 8.0+ 以获得最完善的 instant 支持。
- 在执行 ddl 前,务必查阅官方文档,明确该操作在你的 mysql 版本上支持的算法和锁定行为。
- 在
alter table
语句中显式指定algorithm
和lock
子句(如algorithm=instant, lock=none
),让 mysql 在无法满足要求时报错,而不是默默使用低效的方式。 - 对于大表操作,即使使用 inplace,也应在业务低峰期进行,并监控服务器资源(i/o, cpu, memory)。
- 充分利用
instant
算法进行高频次的表结构变更(如快速加列)。
到此这篇关于深入理解mysql onlineddl的算法的文章就介绍到这了,更多相关mysql onlineddl 内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论