MySQL Online DDL:高性能表结构变更指南

你提供的这段英文内容是 MySQL 官方文档中关于 Online DDL(在线 DDL)性能与并发控制 的详细说明。我们来逐段解析,帮助你深入理解其核心思想和实际意义。


🌟 一、什么是 Online DDL?

Online DDL 是指在执行数据库结构变更(如 ALTER TABLE)时,允许其他查询和写入操作(DML)同时进行,而不需要长时间锁表。

传统方式:ALTER TABLE 会锁住整个表 → 所有读写请求被阻塞 → 用户感知为"卡顿"或"服务中断"。
Online DDL:尽量减少锁,让 DML(INSERT/UPDATE/DELETE)和 SELECT 操作可以继续运行 → 提高系统可用性。


✅ 二、Online DDL 的优势

文档提到了四个关键好处:

优势 解释
1. 更高的应用响应性 应用可以继续访问表,不会因为 DDL 而"挂起"。
2. 减少资源争用 锁更少、等待更少 → 整个数据库的扩展性更好。
3. 避免全表拷贝开销 不用像老的 COPY 算法那样复制整个表 → 节省 I/O 和 CPU。
4. 减少缓冲池污染 不需要大量读取数据到 buffer pool → 常用热数据不会被挤出去 → DDL 后性能不会突然下降。

👉 这些都指向一个目标:在不影响业务的前提下完成表结构变更


🔐 三、LOCK 子句详解:控制并发级别

你可以通过 LOCK = ... 显式控制 DDL 操作期间允许的并发程度。

LOCK 选项 是否允许查询? 是否允许 DML? 使用场景
LOCK=NONE ✅ 是 ✅ 是 关键业务表(如用户注册、订单),不能停服
LOCK=SHARED ✅ 是 ❌ 否 数仓类表,可暂停写入但不能停查询
LOCK=DEFAULT 自动选择最优 自动选择最优 默认行为,推荐大多数情况使用
LOCK=EXCLUSIVE ❌ 否 ❌ 否 只想最快完成 DDL,且服务器空闲

⚠️ 注意:

  • 如果你指定的 LOCK 比实际支持的还宽松(比如你想用 LOCK=NONE,但该操作必须加排他锁),语句会失败。
  • 推荐先不指定 LOCK,让 MySQL 自动决定。

🔁 四、Online DDL 的三个阶段(含元数据锁机制)

Online DDL 并非完全无锁,而是分阶段加锁,以最小化影响。

阶段 1:初始化(Initialization)

  • 判断是否支持并发(基于存储引擎、语句类型、ALGORITHM、LOCK 设置)。
  • 共享可升级元数据锁(shared upgradable metadata lock) → 防止别人改这个表的结构。

阶段 2:执行(Execution)

  • 准备并执行 DDL。
  • 如果需要排他锁,也只是短暂持有

阶段 3:提交表定义(Commit Table Definition)

  • 升级为 排他元数据锁(exclusive metadata lock) → 替换旧表结构,提交新结构。
  • 这个锁时间很短,但必须等到所有并发事务释放锁后才能获得

📌 关键点:

  • 一个长事务(哪怕只是 SELECT)会持有元数据锁 → 导致 DDL 卡住。
  • 一旦 DDL 请求了排他锁,后续所有对该表的操作都会被阻塞,直到 DDL 完成。

🧪 五、案例演示:锁等待问题

sql 复制代码
-- Session 1
START TRANSACTION;
SELECT * FROM t1;  -- 持有共享元数据锁

-- Session 2
ALTER TABLE t1 ADD COLUMN x INT;  -- 等待排他锁(卡住)

-- Session 3
SELECT * FROM t1;  -- 被 Session 2 的等待请求阻塞!

此时:

  • Session 2 在等 Session 1 提交或回滚。
  • Session 3 被 Session 2 "排队挡住了"。

📌 这就是为什么一个简单的 DDL 可能导致整个表"雪崩式"不可用的原因!

🔍 查看方法:

sql 复制代码
SHOW FULL PROCESSLIST;
-- 或使用 Performance Schema
SELECT * FROM performance_schema.metadata_locks;

⚙️ 六、如何判断 DDL 操作快慢?

文档建议用 rows affected 来判断操作是否高效:

操作 示例 rows affected 说明
快速操作(不涉及数据) ALTER TABLE t1 ALTER COLUMN c1 SET DEFAULT 5; 0 rows affected 元数据变更,INSTANT
中等操作(不复制表) ALTER TABLE t1 ADD INDEX idx(c1); 0 rows affected INPLACE,但耗时可能长
慢操作(重建表) ALTER TABLE t1 MODIFY c1 BIGINT; 1671168 rows affected COPY 算法,复制整表

💡 实践建议:

  1. 先克隆一个小表测试 DDL。
  2. 观察 rows affected 是否为 0。
  3. 若非零,说明要复制全表 → 建议在低峰期操作。

📊 七、如何监控 DDL 进度?

使用 Performance Schema 监控:

sql 复制代码
-- 查看当前阶段
SELECT * FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE 'stage/innodb/alter%';

这能告诉你 ALTER TABLE 到了哪一步(如:排序索引、应用日志等)。


🤔 八、为什么 Online DDL 有时比 COPY 更慢?

这是个反直觉的现象,原因如下:

  • Online DDL 支持并发 DML → 必须记录这些并发修改(称为"log")。
  • 在 DDL 结束前,要把这些"增量变更"合并回去。
  • 这个过程增加了总耗时。

✅ 但是:

  • 虽然总时间更长,但用户体验更好(页面不卡)。
  • 对比:
    • COPY:快但全程锁表 → 用户卡 30 秒。
    • INPLACE:慢一点但用户几乎无感。

📌 所以,"性能"不只是速度,还包括可用性和响应性


✅ 总结:如何理解这段内容?

核心概念 理解要点
Online DDL 的目标 在不影响业务的情况下修改表结构
实现方式 尽量避免锁表,使用 INPLACE / INSTANT 算法
LOCK 子句 控制并发级别,按需选择 NONE / SHARED / EXCLUSIVE
元数据锁(MDL) DDL 最后一步需要排他锁,可能被长事务阻塞
性能判断 rows affected:0 表示不复制表,非 0 表示重建表
监控手段 SHOW PROCESSLISTperformance_schema 查锁和进度
权衡取舍 Online 更稳但可能稍慢;COPY 更快但会中断服务

💡 实际建议(给 DBA 和开发)

  1. 避免长事务,尤其是只读事务不要长时间不提交。
  2. 大表变更前先测试小表 ,看是否 rows affected > 0
  3. 优先使用 ALGORITHM=INPLACEINSTANT
  4. 生产环境 DDL 加上 LOCK=NONELOCK=SHARED,防止意外锁死。
  5. 监控 MDL 锁等待,及时发现阻塞源头。

如果你有具体的场景(比如:"我想给一个千万级订单表加字段,怎么做?"),我可以进一步给出操作建议。

相关推荐
阿沁QWQ2 小时前
MySQL程序简介
数据库·mysql
一 乐2 小时前
社区互助养老系统|基于java和小程序的社区互助养老系统小程序设计与实现(源码+数据库+文档)
java·数据库·spring boot·小程序·论文·毕设·社区互助养老系统小程序
Java水解4 小时前
MySQL 表约束实战指南:从概念到落地,守护数据完整性
后端·mysql
tingting01194 小时前
mysql 8.4.2 备份脚本
android·数据库·mysql
铜峰叠翠5 小时前
Redis安装配置
数据库·redis·缓存
William_cl5 小时前
【连载1】《假装自己是个小白 —— 重新认识 MySQL》实践指南
android·mysql·oracle
Lbwnb丶5 小时前
JUnit 4 + Spring Boot 测试依赖
数据库·spring boot·junit
大筒木老辈子5 小时前
MySQL笔记---表的约束
数据库·笔记·mysql
涤生大数据5 小时前
从MR迁移到Spark3:数据倾斜与膨胀问题的实战优化
数据库·数据仓库·spark·mapreduce·大数据开发·数据倾斜·spark3