判断alter是否走online ddl应查官方支持矩阵或观察show processlist中是否出现“copy to tmp table”;instant仅限8.0.12+末尾加列等极窄场景;lock=none不等于零阻塞,仍受mdl锁、buffer pool污染等影响。

怎么判断一个ALTER是否走Online DDL
直接看执行计划或EXPLAIN没用,MySQL不暴露DDL执行路径。真正可靠的方式是查INFORMATION_SCHEMA.INNODB_METRICS或观察SHOW PROCESSLIST中是否长时间卡在copy to tmp table——出现这个状态,基本就是走COPY算法了。
更实用的做法是查官方文档的Online DDL支持矩阵,对照你的操作类型和MySQL版本。比如:ADD INDEX在5.6+全版本都走INPLACE;ADD COLUMN在8.0.12+末尾加字段可走INSTANT;但MODIFY COLUMN哪怕只是把VARCHAR(10)改成VARCHAR(20),在8.0.33之前仍可能触发COPY。
- 别信“默认就Online”——MySQL的
ALGORITHM=DEFAULT会优先选INPLACE,但某些操作(如改字符集)根本无法INPLACE,它就会退化到COPY - 用
ALGORITHM=INPLACE强制指定后,如果操作不支持,会报错ERROR 1845 (HY000): ALGORITHM=INPLACE is not supported,而不是静默降级 -
LOCK=NONE不是万能开关:即使算法支持INPLACE,若操作本身需排他锁(如删主键),LOCK=NONE会直接失败,报错ERROR 1846 (HY000): LOCK=NONE is not supported
什么时候必须用pt-online-schema-change而不是原生Online DDL
原生Online DDL不是万能解药。当遇到以下任一情况,就得切到pt-online-schema-change:
-
ALTER TABLE语句被MySQL判定为必须COPY,且你没法改操作方式(比如要给大表CHANGE COLUMN类型,又不能升级到8.0.33+) - 主从延迟敏感:原生
INPLACE操作虽允许DML并发,但DDL期间产生的row log要等commit阶段才合并,从库回放压力集中,容易拉长延迟 - 需要中途暂停或限速:原生DDL一旦开始就停不了,
pt-osc支持--max-load、--check-interval等参数动态控速 - DDL变更涉及外键或触发器——
pt-osc会自动处理影子表的外键重建和触发器迁移,原生DDL容易漏掉依赖对象
注意:pt-osc不是零成本。它会在原库多占一份磁盘(影子表+触发器日志),且对高QPS写入场景,触发器开销可能推高CPU。上线前务必在备库压测。
INSTANT DDL的硬性限制和绕过技巧
ALGORITHM=INSTANT只在8.0.12+有效,且仅覆盖极窄的操作集:末尾加列、改列默认值、删列(8.0.29+)、重命名列(8.0.29+)。但它有个关键隐性约束:所有历史行查询时都要补默认值,所以新增列必须带DEFAULT。
- 没写
DEFAULT?MySQL会拒绝执行,报错ERROR 3105 (HY000): Cannot add column with non-default value in INSTANT algorithm - 想在中间插字段?不行。8.0.29起支持
AFTER col_name语法,但底层仍是INPLACE而非INSTANT,性能无提升 - 已有数据的表,
INSTANT加的列在查询旧数据时“看起来”有值(默认值),但磁盘上那行实际没存这个字段——这是元数据版本控制的结果,别试图用SELECT * FROM t WHERE new_col IS NULL去筛数据,永远查不到
如果业务真需要中间加字段,又卡在INSTANT限制里,唯一办法是接受一次INPLACE重建:先末尾加字段,再用ALTER TABLE ... MODIFY COLUMN调整顺序(这步会触发INPLACE rebuild,但比全表COPY快得多)。
LOCK=NONE失效的典型场景
LOCK=NONE常被当成“完全不锁表”的银弹,实际它只保证DML不被阻塞,但以下情况仍会导致业务感知卡顿:
- MDL锁争抢:DDL准备阶段会短暂申请
MDL_EXCLUSIVE,如果此时有长事务正在查这张表,DDL会被堵住,而所有新来的DML也会排队等这个MDL——表现为“突然所有写入变慢”,查performance_schema.metadata_locks能看到堆积 - Buffer Pool污染:
INPLACE重建索引时,会批量读取数据页进内存,挤出热点页。后续查询可能因缓存命中率下降而变慢,尤其在buffer pool不够大的实例上 - Binlog写放大:Online DDL期间产生的row log最终要刷成binlog event,如果DDL耗时长,binlog写入会持续占用IO,影响主从同步吞吐
真正要“零感知”,得组合策略:挑低峰期执行 + 确保没有未提交长事务 + innodb_buffer_pool_size预留20%余量 + 监控Innodb_rows_read和Bytes_received突增。单靠LOCK=NONE解决不了根本问题。











