MySQL & MariaDB Online DDL参考指南


MySQL & MariaDB Online DDL参考指南文章插图
概述在早期的 MySQL 版本中 , DDL 操作(如创建索引等)通常都需要对数据表加锁 , 操作过程中 DML 操作都会被阻塞 , 影响正常业务 。 MySQL 5.6 和 MariaDB 10.0 开始支持 Online DDL , 可以在执行 DDL 操作的同时 , 不影响 DML 的正常执行 , 线上直接执行 DDL 操作对用户基本无感知(部分操作对性能有影响) 。
不同版本的数据库对各种 DDL 语句的支持存在一定的差异 , 本文将会针对 MySQL 和 MariaDB 对 Online DDL 的支持情况做一个汇总 , 在需要执行 DDL 操作时 , 可以参考本文的 Online DDL 支持情况 部分 。
本文将会持续修正和更新 , 最新内容请参考我的 GITHUB 上的 程序猿成长计划 项目 , 欢迎 Star , 更多精彩内容请 follow me 。
在 ALTER TABLE 语句中 , 支持通过 ALGORITHM 和 LOCK 语句来实现 Online DDL:

  • ALGORITHM - 控制 DDL 操作如何执行 , 使用哪个算法
  • LOCK - 控制在执行 DDL 时允许对表加锁的级别
ALTER TABLE tab ADD COLUMN c varchar(50), ALGORITHM=INPLACE, LOCK=NONE;ALGORITHM 支持的算法
MySQL & MariaDB Online DDL参考指南文章插图
NOCOPY 算法支持:MariaDB 10.3.2+ , MySQL 不支持该算法 。
INSTANT 算法支持:MariaDB 10.3.2+ , MySQL 8.0.12+ 。
算法使用规则:
  • 如果用户指定的算法为 COPY , 则 InnoDB 使用 COPY 算法 。
  • 如果用户指定的是 COPY 之外的其它算法 , 则 InnoDB 会按照算法效率 , 选择最高效的算法 , 最差的情况下采用用户指定的算法 。 比如用户指定了 ALOGRITHM = NOCOPY , 则 InnoDB 会从 (NOCOPY, INSTANT) 中选择支持的最高效的算法 。

MySQL & MariaDB Online DDL参考指南文章插图
MySQL 服务主要为 Server 层 和 存储引擎层 两部分组成 , Server 层包含了 MySQL 大部分核心功能 , 所有的内置函数 , 跨存储引擎的功能如存储过程、触发器、视图等 。 存储引擎层负责数据的存储和读取 , 采用了插件式的架构模式 。
COPY 算法 作用在 Server 层 , 其执行过程都是在 Server 层 , 因此所有存储引擎都支持使用该算法 , 执行过程如下图
MySQL & MariaDB Online DDL参考指南文章插图
INPLACE 算法 作用于存储引擎层 , 是 InnoDB 存储引擎特有的 DDL 算法 , 执行过程如下图所示
MySQL & MariaDB Online DDL参考指南文章插图
LOCK 策略默认情况下 , MySQL/MariaDB 在执行 DDL 期间会使用尽可能少的锁 , 如果必要 , 可以通过 LOCK 子句控制在执行 DDL 时允许对表加锁的级别 。 如果指定的操作所要求的限制级别不满足(EXCLUSIVE > SHARED > NONE) , 则语句执行失败并报错 。
MySQL & MariaDB Online DDL参考指南文章插图
为了避免执行 DDL 时 , 由于锁表导致生产服务不可用 , 在执行表结构变更语句时 , 可以添加 LOCK=NONE 子句 , 如果语句需要获取共享锁或者排它锁 , 则会直接报错 , 这样就可以避免意外锁表 , 造成线上服务不可用了 。
Online DDL 执行过程Online DDL 操作主要分为三个阶段:
MySQL & MariaDB Online DDL参考指南文章插图
  • 阶段 1:初始化在初始化阶段 , 服务器会根据存储引擎的能力 , 操作的语句和用户指定的 ALGORITHM 和 LOCK 选项来决定允许多大程度的并发 。 在这个阶段会创建一个 可升级的元数据共享锁(SU)来保护表定义 。
  • 阶段 2:执行这个阶段会 准备 并 执行 DDL 语句 , 根据 阶段 1 评估的结果来决定是否将元数据锁升级为 排它锁 (X) , 如果需要升级为排它锁 , 则只在 DDL 的 准备阶段 短暂的添加排它锁 。
  • 阶段 3:提交表定义在表定义的提交阶段 , 元数据锁会升级为排它锁来更新表的定义 。 独占排它锁的持续时间非常短 。
元数据锁(MDL , Metadata Lock)主要用于 DDL 和 DML 操作之间的并发访问控制 , 保护表结构(表定义)的一致 , 保证读写的正确性 。 MDL 不需要显式的使用 , 在访问表时会自动加上 。
由于上面三个阶段中对元数据锁的独占 ,Online DDL 过程必须等待已经持有元数据锁的并发事务提交或者回滚才能继续执行 。
注意:当 Online DDL 操作正在等待元数据锁时 , 该元数据锁会处于挂起状态 , 后续的所有事务都会被阻塞 。 在 MariaDB 10.3 之后 , 可以通过添加 NO WAIT 或者 WAIT n 来控制等待所得超时时间 , 超时立即失败 。