MySQL 5.7+原生Online DDL添加二级索引默认支持ALGORITHM=INPLACE且允许并发DML,但仅在开始和结束阶段短暂持有MDL SHARED/EXCLUSIVE锁;若条件不满足则退化为COPY模式并全表锁。

MySQL 5.7+ 原生 Online DDL 能否直接用
能,但必须满足具体条件,不是所有 ALTER TABLE 都自动“在线”。关键看操作类型和参数组合。
添加二级索引、添加列(非首列)、修改列默认值等,在 InnoDB 表上可走 ALGORITHM=INPLACE;但加主键、改列类型(如 VARCHAR(255) → VARCHAR(500))、或表上有全文索引时,可能退化为 COPY 模式,照样锁表。
- 务必显式指定
ALGORITHM=INPLACE, LOCK=NONE,不写等于默认由 MySQL 自行决策,结果不可控 -
LOCK=NONE仅在支持并发 DML 的操作中才有效;若语句隐含需要排他锁(如修改主键),MySQL 会直接报错:ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported... - 执行前先查
information_schema.innodb_trx,确保没有运行超 60 秒的长事务——否则 DDL 会被卡在元数据锁等待队列里,连带阻塞后续所有读写
pt-online-schema-change 触发器带来的真实风险
它确实不锁原表,但触发器本身是双刃剑:高并发写入下,INSERT/UPDATE/DELETE 触发器会与原表 DML 竞争行锁,尤其当原表有唯一键冲突、或触发器内 SQL 执行慢时,容易引发锁等待甚至死锁。
- 必须提前关闭
innodb_autoinc_lock_mode=0或1,否则自增列写入会严重串行化;推荐设为2(交错模式) - 触发器逻辑不可被中断,一旦 pt-osc 进程崩溃,残留触发器会持续向影子表写脏数据,需人工清理:
DROP TRIGGER IF EXISTS `trg_ins_old_table` - 不要在从库上运行 pt-osc,binlog 中触发器语句不会重放,会导致主从数据不一致
gh-ost 为什么比 pt-osc 更适合高一致性场景
它不依赖触发器,而是通过伪装成从库拉取 binlog,并把变更解析后应用到影子表。这意味着:原表完全无额外负担,没有触发器锁争用,也没有因事务回滚导致的影子表数据错乱问题。
- binlog 必须开启
ROW格式,且binlog_row_image=FULL,否则 UPDATE/DELETE 可能丢失旧值,同步失败 - gh-ost 默认不阻塞原表 DML,但
RENAME TABLE切换瞬间仍需短暂表级锁(毫秒级),业务敏感度极高时需配合应用层双写兜底 - 它会主动探测主从延迟,延迟超过阈值(默认 1 秒)自动暂停迁移,避免雪崩式延迟堆积
DDL 执行中如何判断是否真“在线”
不能只看 SHOW PROCESSLIST 里状态是不是 altering table,那只是表面;真正要盯的是是否产生阻塞链路。
- 实时查
performance_schema.data_locks,过滤OBJECT_SCHEMA和OBJECT_NAME,确认没有TABLE级或GLOBAL级的X锁长期持有 - 监控
information_schema.INNODB_METRICS中dml_reads、dml_writes是否持续有流量,而非归零或骤降 - 如果应用层出现大量
Lock wait timeout exceeded或Deadlock found,说明 DDL 已实际干扰业务,应立即中止并切回备用方案
RENAME 阻塞,有些连 1ms 的延迟毛刺都不能有。选方案前,先拿真实流量压测,比读文档更管用。


















