当前位置: 首页 > news >正文

讲解Mysql OnlineDDL的算法

         MySQL 5.6 及以后版本(尤其是 InnoDB 存储引擎)引入的一项极其重要的功能,它允许数据库管理员在执行 ALTER TABLE 操作时,最大程度地减少对表锁定和应用程序可用性的影响

        核心目标: 在 DDL 操作进行时,允许对表进行并发读取(SELECT) 和写入(INSERT, UPDATE, DELETE) 操作。

一、传统的 DDL (Copy Algorithm)

在 Online DDL 出现之前,主要的 DDL 操作算法是 COPY

  • 创建临时表: 根据新的表结构创建一个空的新临时表。

  • 锁表: 对原表施加一个排他锁 (X Lock)。此时,任何对该表的读写操作都会被阻塞。

  • 复制数据: 将原表中的数据逐行复制到新临时表中。

  • 应用修改: 在复制过程中或复制完成后,应用 DDL 语句定义的更改(如添加索引、修改列等)。

  • 交换表名: 数据复制完成后,将原表删除(或重命名),并将新临时表重命名为原表名。

  • 释放锁: 完成重命名后,释放排他锁。

优点: 实现简单,兼容性好。

致命缺点: 在步骤 2 到步骤 5 期间,表完全不可用。对于大表,这可能导致长时间的停机窗口,对在线业务是灾难性的。需要双倍存储空间(原表 + 新表)。

二、Online DDL 的三种主要算法

2.1 COPY (Online-Capable with Locking)

  • 本质: 是传统 COPY 算法的变种,但努力减少锁定时间

  • 过程:

    • 创建临时表。

    • 在原表上加 SHARED 锁(允许读,阻塞写)。

    • 将原表数据复制到临时表。

    • 在临时表上应用 DDL 更改。

    • 短暂申请 EXCLUSIVE 锁(阻塞读写)。

    • 交换表名。

    • 释放锁。

  • 锁时间: 大部分时间持有 SHARED 锁(阻塞写),最后交换时持有短暂的 EXCLUSIVE 锁(阻塞读写)。

  • 空间: 需要双倍存储空间。

  • 并发性: 允许读,阻塞写。

  • 适用场景: 通常是一些无法使用 INPLACE 的操作(如删除主键、修改某些列类型)。MySQL 会尽量优先选择 INPLACE 或 INSTANT。在 ALGORITHM=COPY 或 old_alter_table=ON 时强制使用。

2.2 INPLACE (Online-Capable)

  • 本质: 操作尽可能在原表空间内进行避免重建整个表。这是 Online DDL 的主力算法。

  • 过程:

    • 准备阶段:

      • 对表加 SHARED_NO_WRITE 锁(或类似元数据锁 MDL)。此时允许读,阻塞写。

      • 创建新的临时文件(如 .ibd.frm 临时文件),准备所需资源(如新索引的 B+树结构)。

    • 执行阶段:

      • 降级为 SHARED 锁(MySQL 5.6)或更宽松的元数据锁(MySQL 5.7+)。此时允许读写!(这是关键进步)

      • 在后台应用更改(如逐行读取数据构建新索引、合并 B+树页、原地修改页结构等)。这个过程通常是最耗时的,但允许并发读写。

    • 提交阶段:

      • 短暂申请 EXCLUSIVE 锁(阻塞读写)。

      • 将执行阶段产生的更改(日志、临时文件)应用到原表,更新数据字典元数据。

      • 清理临时文件。

      • 释放锁。

  • 锁时间: 准备和提交阶段有短暂的锁定(主要是阻塞写),执行阶段允许并发读写。整体锁定时间远小于 COPY 算法。

  • 空间: 通常只需要额外的日志空间(用于记录并发 DML)和临时排序文件空间(如建索引时),不需要完整的双倍表空间(除非操作本身需要,如 OPTIMIZE TABLE)。但磁盘 IO 和 CPU 开销仍然较大。

  • 并发性: 执行阶段允许并发读写,这是其被称为 "Online" 的关键。

  • 适用场景: 绝大多数 DDL 操作都支持 INPLACE,如添加/删除二级索引、修改默认值、添加/删除列(8.0 前)、修改 VARCHAR 列长度(不缩小)、OPTIMIZE TABLE、表重建等。

2.3 INSTANT (Online-Capable)

  • INSTANT (Online-Capable)

    • 本质: MySQL 8.0 引入的革命性算法。操作只修改数据字典元数据(metadata)几乎不修改表数据本身。速度极快(毫秒级)。

    • 过程:

      • 对表施加一个极其短暂的 EXCLUSIVE 元数据锁。

      • 在数据字典中记录变更信息(如在表的元数据中记录新增列的定义、默认值;或在每行记录的头部信息中标记该行是否应用了新的默认值)。

      • 释放锁。

      • 对于新增列:

        • 如果指定了默认值(包括 NULL),DDL 完成后立即查询该列,对于 DDL 执行前存在的行 (old rows),MySQL 在读取时会即时计算 (INSTANT) 并返回默认值(或 NULL)。该默认值不会物理存储在这些旧行中。

        • 对于 DDL 执行后插入的新行 (new rows),默认值会物理存储在行记录中。

        • 可以通过 ALTER TABLE ... ALGORITHM=INSTANT 强制尝试使用,但如果不支持会自动回退到 INPLACE 或 COPY。

    • 锁时间: 极其短暂的元数据锁(毫秒级)。

    • 空间: 几乎不占用额外空间(仅少量元数据)。是空间效率最高的算法。

    • 并发性: 几乎不影响读写,锁定时间可忽略不计。

    • 适用场景 (MySQL 8.0+):

      • 添加列(需满足条件,如加在最后、不支持 FULLTEXT/SPATIAL 等特殊索引、某些数据类型限制等)。

      • 删除列(需满足条件,MySQL 8.0.29+)。

      • 添加或删除虚拟列 (Virtual Column)。

      • 添加或删除列默认值 (SET DEFAULTDROP DEFAULT)。

      • 修改 ENUM 或 SET 列的定义(在末尾添加新选项)。

      • 修改索引类型(如 BTREE 转 HASH,反之亦然,但 InnoDB 只支持 BTREE)。

      • 重命名表 (RENAME TABLE)。

      • 设置/删除表的 PERSISTENT 统计信息选项。

      • 更多操作在后续 MySQL 版本中不断加入(如 DROP 索引 8.0.12+, RENAME 索引 8.0.13+ 等)。务必查阅对应版本的官方文档。

2.4 关键区别总结

特性COPY AlgorithmINPLACE AlgorithmINSTANT Algorithm (8.0+)
核心方式重建整个表原地修改,避免重建整个表仅修改元数据
锁表时间 (全程锁或长写锁) (准备/提交锁)极短 (毫秒级元数据锁)
执行阶段不允许读写允许并发读写允许并发读写
空间占用双倍表空间额外日志/临时文件空间几乎无额外空间
速度中等 (取决于操作复杂度)极快 (毫秒级)
并发影响高 (停机)低 (短暂阻塞写)极低 (几乎无感知)
主要优势兼容性平衡性能和并发瞬时完成,零感知
典型操作部分无法 INPLACE 的操作 (如删除主键)添加/删除索引、修改列属性等添加/删除列 (有条件)、改默认值

 2.5 如何指定和查看算法

  • 指定算法: 在 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 观察进度(对于长时间操作),或者直接执行后观察输出信息(很多客户端会显示使用的算法)。最准确的是查看官方文档对具体操作的支持矩阵。

 2.6 重要注意事项

  • 并非所有 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 通过 COPYINPLACEINSTANT 三种算法,极大地提升了 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 算法进行高频次的表结构变更(如快速加列)。

http://www.xdnf.cn/news/1155619.html

相关文章:

  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘lxml’问题
  • docker Neo4j
  • 【RK3576】【Android14】显示屏MIPI开发调试
  • 【图文详解】Transformer架构详细解析:多头自注意力机制、qkv计算过程、encoder架构、decoder架构以及mask的意义
  • Qwen3-8B 与 ChatGPT-4o Mini 的 TTFT 性能对比与底层原理详解
  • 网鼎杯2020青龙组notes复现
  • springboot websocket 自动重启方案
  • 彩虹云商城全源码 - 全新客服系统上线
  • CAN通讯理论与实践:调试和优化全讲解
  • 移动端开发的package命名规范
  • 《突破 GIL 限制:Python 多线程的真相与最佳实践》
  • “人工智能+”视域下计算思维与语文写作融合的跨学科教学设计模式探究
  • OpenTelemetry学习笔记(九):Elastic 对 OTLP 的原生支持
  • 二、Spark 开发环境搭建 IDEA + Maven 及 WordCount 案例实战
  • Golang的微服务链路追踪
  • 7. 命令模式
  • 5G NR PDCCH之CRC处理
  • GaussDB 数据库架构师修炼(七) 安全规划
  • 【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
  • 常用框架知识
  • Python基础-列表
  • 【Lua】大G表
  • 06 51单片机之矩阵键盘
  • 【Kafka】深入理解 Kafka MirrorMaker2 - 实战篇
  • 链表的基本操作
  • 费曼学习法
  • 吴恩达机器学习笔记(3)—线性代数回顾(可选)
  • 嵌入式硬件篇---按键
  • Nginx的location匹配规则
  • Android 项目中如何在执行 assemble 或 Run 前自动执行 clean 操作?