MySQL 5.7的Online DDL不原子且非真正无锁,因ALGORITHM=INPLACE仅避免全表拷贝,仍需短暂LOCK=SHARED或EXCLUSIVE锁,且不支持事务回滚,失败易留半成品状态。

MySQL 5.7 的 Online DDL 并不真正“原子”,ALGORITHM=INPLACE 操作仍可能在执行中途失败并留下半成品状态,必须配合显式参数控制和前置验证才能降低风险。
为什么 ALTER TABLE ... ALGORITHM=INPLACE 在 5.7 里不等于无锁
5.7 支持的 INPLACE 是指避免全表拷贝,但不代表全程无锁。它仍需短暂获取 LOCK=SHARED(阻塞写)或 LOCK=EXCLUSIVE(读写全阻),尤其在操作开始和结束阶段:
- 添加二级索引时,末尾会短暂加
EXCLUSIVE锁完成元数据切换 - 修改
VARCHAR长度(仅增大)虽不重写行数据,但需重写索引项,触发SHARED锁 -
RENAME COLUMN在 5.7 中是INPLACE,但要求表上无长事务或未提交 DML,否则卡在等待 MDL 锁 - 错误日志里出现
Waiting for table metadata lock就是典型征兆,不是语句写错,而是被其他连接占着锁
ALGORITHM=INPLACE, LOCK=NONE 报错的常见原因
显式指定这两个参数本意是追求最高并发性,但 5.7 实际支持范围有限,报错往往源于隐含约束:
-
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported:说明该操作在当前表结构下无法跳过数据重写,比如字段含NULL值却要设NOT NULL -
ERROR 1847 (HY000): LOCK=NONE is not supported:即使算法支持,某些变更(如修改主键、调整ROW_FORMAT)仍强制需要共享锁 - 表使用了
MyISAM或非InnoDB引擎:Online DDL 仅对InnoDB生效 - MySQL 5.7.5 之前版本不支持
LOCK=NONE与ADD COLUMN组合;5.7.23+ 才稳定支持MODIFY COLUMN增大VARCHAR
如何判断一个 ALTER 是否真能在线执行
别依赖文档列表,用实际命令试探最可靠:
- 先加
ALGORITHM=INPLACE, LOCK=NONE执行,看是否直接报错;若成功,再查information_schema.innodb_alter_table确认进度 - 对大表,务必在低峰期执行,并提前运行:
SELECT * FROM information_schema.innodb_trx WHERE TIME > 60;清掉长事务 - 监控 MDL 锁:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_NAME = 'your_table';(需开启performance_schema) - 注意 binlog 格式:若为
STATEMENT,某些INPLACE操作在从库会退化为COPY,导致主从延迟飙升
大表改结构时,pt-online-schema-change 不是银弹
它用影子表 + 触发器绕过原生 DDL 限制,但自身有硬伤:
- 触发器开销真实存在:每条
INSERT/UPDATE/DELETE都多一次同步写入,QPS 高时 CPU 和 I/O 明显上涨 - 不能用于有外键引用的表(除非加
--alter-foreign-keys-method=auto,但会额外锁父表) - 若原表无主键或唯一索引,
pt-osc会拒绝执行——它靠主键分块拷贝,没主键就无法切片 - 执行中若中断,残留的
_table_new和触发器需手动清理,否则下次执行会冲突
真正难处理的是那些既不支持 INPLACE、又无法停机、还带外键的大表——这时候得拆成多步:先加扩展字段(JSON 类型),业务层兼容新旧逻辑,再逐步迁移数据,最后删旧列。这种事没法一键解决。


















