MySQL在线DDL:零停机改表实战指南

你提供的这段内容是 MySQL 官方文档的 17.12 节:InnoDB and Online DDL ,它详细介绍了 MySQL(尤其是 InnoDB)从 5.6 开始引入并持续优化的一项核心功能:在线 DDL(Online DDL)


🌟 一句话总结:

Online DDL 允许你在修改表结构(如加字段、建索引等)的同时,依然可以正常读写数据,几乎不影响业务运行。

这在现代高可用、高并发的生产环境中至关重要。


我们来逐段深入解读,并用通俗语言 + 实战建议帮助你理解。


🔹 17.12.1 Online DDL Operations(支持的在线 DDL 操作)

✅ 什么是 Online DDL?

传统的 ALTER TABLE 会锁表、复制整个表,耗时长、服务中断。而 Online DDL 改进了这一点:

  • Instant(瞬间完成):某些操作只需修改元数据,不碰数据文件。
  • In-Place(原地修改):不创建临时表,直接在原表上改,但仍需少量锁。
  • Copy(表复制):老方式,效率低,已尽量避免。

📊 不同操作类型对比(MySQL 8.0+)

操作 ALGORITHM 是否在线? 说明
ADD COLUMN(末尾) INSTANT(8.0.12+) ✅ 几乎无锁 只改元数据
ADD INDEX INPLACE ✅ 支持 DML 构建索引时允许读写
DROP INDEX INPLACE ✅ 完全在线 删除快
MODIFY COLUMN 类型变更 COPYINPLACE ❌/⚠️ 大部分需要复制表
ADD PRIMARY KEY INPLACE ✅ 但需排序 可能较慢
CHANGE COLUMN 名称或类型 多数 COPY 不推荐在线做

💡 提示:INSTANT 是 MySQL 8.0.12 的重大优化,比如加字段几乎"零延迟"。


🔹 17.12.2 Online DDL Performance and Concurrency(性能与并发控制)

⚙️ 你可以通过两个关键子句控制行为:

1. ALGORITHM={INSTANT \| INPLACE \| COPY}

  • 强制使用某种算法。
  • 用于调试或降级兼容。

2. LOCK={DEFAULT \| NONE \| SHARED \| EXCLUSIVE}

  • 控制 DDL 期间的并发级别。
LOCK 级别 允许 SELECT? 允许 DML(INSERT/UPDATE/DELETE)? 场景
LOCK=NONE 最宽松,适合高并发系统
LOCK=SHARED 只读可用,防写入
LOCK=DEFAULT 自动选择 自动选择 默认行为
LOCK=EXCLUSIVE 完全锁表,慎用

✅ 推荐做法:

sql 复制代码
ALTER TABLE users ADD COLUMN phone VARCHAR(20), 
    ALGORITHM=INPLACE, 
    LOCK=NONE;

这样如果无法做到"不锁",语句会立即失败,而不是卡住生产环境。


🔹 17.12.3 Online DDL Space Requirements(空间需求)

💾 空间消耗对比

算法 是否需要额外空间? 说明
ALGORITHM=INSTANT ❌ 几乎不需要 只改字典
ALGORITHM=INPLACE ⚠️ 少量 需要日志空间、排序缓冲等
ALGORITHM=COPY ✅ 需要 ≥ 2倍表大小 创建临时表 .tmp,风险高

📌 举例:一个 50GB 的表执行 ALGORITHM=COPY,需要至少 100GB 磁盘空间!

✅ 建议:

  • 监控磁盘空间。
  • 尽量避免 COPY 模式。

🔹 17.12.4 Online DDL Memory Management(内存管理)

  • Online DDL 在构建索引或重做表时会使用缓冲区。
  • 主要参数:
    • innodb_sort_buffer_size:排序用内存。
    • innodb_online_alter_log_size:记录 DDL 过程中 DML 变更的日志大小。

⚠️ 如果 DDL 期间有大量写入,这个日志可能溢出,导致失败。

✅ 建议:

  • 对大表 DDL,提前增大:

    sql 复制代码
    SET GLOBAL innodb_online_alter_log_size = 1073741824; -- 1GB

🔹 17.12.5 Configuring Parallel Threads for Online DDL(并行线程配置)

从 MySQL 8.0 起,某些 DDL 操作(如创建二级索引)可以并行执行,显著提升速度。

  • 使用参数:innodb_parallel_read_threads(默认 4)
  • 适用于:ADD INDEX 等 I/O 密集型操作。

✅ 示例:

sql 复制代码
-- 提高并行度
SET SESSION innodb_parallel_read_threads = 8;
ALTER TABLE orders ADD INDEX idx_user_id (user_id);

💡 类似于"多个人一起搬砖",加快索引构建。


🔹 17.12.6 Simplifying DDL Statements with Online DDL(简化 DDL 语句)

不需要每次都写 ALGORITHMLOCK,MySQL 默认会自动选择最优方式。

但你可以显式指定以确保安全:

sql 复制代码
-- 安全写法:必须在线,否则失败
ALTER TABLE logs ADD COLUMN status TINYINT,
    ALGORITHM=INPLACE,
    LOCK=NONE;

✅ 好处:防止意外锁表,适合自动化脚本。


🔹 17.12.7 Online DDL Failure Conditions(失败情况)

以下情况会导致 Online DDL 失败或退化为 COPY

  1. 使用了不支持 INPLACE 的操作(如改变列字符集)。
  2. 指定的 LOCK 级别无法满足(如要求 LOCK=NONE 但实际需要锁)。
  3. 磁盘空间不足。
  4. innodb_online_alter_log 溢出(DDL 期间写入太多)。
  5. 存在外键约束限制。

✅ 建议:在测试环境先试,查看 SHOW ENGINE INNODB STATUS 中的 DDL 日志。


🔹 17.12.8 Online DDL Limitations(限制)

当前仍有一些限制:

限制 说明
不支持 JSON 列的某些修改 如修改嵌套结构
分区表 DDL 更复杂 部分操作仍需锁表
ALTER TABLE ... RENAME COLUMN 8.0+ 支持,但底层可能是 COPY
外键约束可能阻止 LOCK=NONE 需注意依赖关系
ROW_FORMAT 修改可能触发复制 尤其是 COMPRESSED

✅ 实战建议(DBA 必看)

场景 推荐做法
加字段(末尾) MySQL 8.0.12+ 用 ADD COLUMN → 几乎无感
加索引 ALGORITHM=INPLACE, LOCK=NONE,避免高峰期
改字段类型 小心!可能触发 COPY,先评估
删除字段 支持 INPLACE,但建议先测试
生产环境 DDL 永远加上 LOCK=NONELOCK=SHARED,防止锁库
大表操作 提前调大 innodb_online_alter_log_size,开启并行

🧪 示例:安全地在线加字段和索引

sql 复制代码
-- 1. 加字段(MySQL 8.0.12+ 瞬间完成)
ALTER TABLE users 
    ADD COLUMN email VARCHAR(100) AFTER name,
    ALGORITHM=INSTANT,
    LOCK=NONE;

-- 2. 加索引(允许读写)
ALTER TABLE users 
    ADD INDEX idx_email (email),
    ALGORITHM=INPLACE,
    LOCK=NONE;

-- 3. 查看是否成功
SHOW PROCESSLIST; -- 观察是否有阻塞

📈 总结:Online DDL 的三大优势

优势 说明
高可用性 表不锁,服务不中断
节省空间 避免 COPY 模式占用双倍磁盘
提升效率 并行 + 快速算法(如 INSTANT)

🚨 最后提醒

不要以为所有 DDL 都是"在线"的!

一定要:

  1. 查看 MySQL 官方文档 确认操作是否支持 Online。
  2. 在测试环境验证。
  3. 生产环境使用 ALGORITHMLOCK 显式控制行为。

如果你有具体的 DDL 语句想知道是否"在线",或者想分析某个 DDL 为什么卡住了,欢迎贴出来,我可以帮你分析!

相关推荐
麦聪聊数据13 分钟前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
AC赳赳老秦1 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
myzshare2 小时前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序
YMatrix 官方技术社区2 小时前
YMatrix 存储引擎解密:MARS3 存储引擎如何超越传统行存、列存实现“时序+分析“场景性能大幅提升?
开发语言·数据库·时序数据库·数据库架构·智慧工厂·存储引擎·ymatrix
辞砚技术录3 小时前
MySQL面试题——索引2nd
数据库·mysql·面试
linweidong3 小时前
C++thread pool(线程池)设计应关注哪些扩展性问题?
java·数据库·c++
墨笔之风3 小时前
java后端根据双数据源进行不同的接口查询
java·开发语言·mysql·postgres
欧亚学术4 小时前
突发!刚刚新增17本期刊被剔除!
数据库·论文·sci·期刊·博士·scopus·发表
黑白极客4 小时前
怎么给字符串字段加索引?日志系统 一条更新语句是怎么执行的
java·数据库·sql·mysql·引擎
大厂技术总监下海4 小时前
数据湖加速、实时数仓、统一查询层:Apache Doris 如何成为现代数据架构的“高性能中枢”?
大数据·数据库·算法·apache