mysql 5.7大表alter table锁表时间长的根本原因是多数结构变更强制走全表拷贝重建流程,全程持有mdl_exclusive锁;pt-online-schema-change通过影子表+触发器绕开mdl锁,实现近零停机。

MySQL 5.7 执行大表 ALTER TABLE 时锁表时间长,根本原因不是“没加 ALGORITHM=INPLACE”,而是多数结构变更**强制走拷贝重建流程**,且该流程全程持有排他性元数据锁(MDL)和表级写锁。
为什么5.7默认走拷贝重建而不是就地修改
MySQL 5.7 的 Online DDL 支持有限:只有少数操作(如末尾 ADD COLUMN、DROP COLUMN、ADD INDEX)能真正用 ALGORITHM=INPLACE;其余绝大多数变更——包括 MODIFY COLUMN、CHANGE COLUMN、CONVERT TO CHARACTER SET、添加 NOT NULL DEFAULT 值到非空表——都会触发全表重建。
- 重建流程固定为:创建临时表 → 逐行
INSERT INTO ... SELECT拷贝 → 重建所有索引(含排序)→ 原子RENAME - 这个过程从开始到
RENAME完成前,始终持有MDL_EXCLUSIVE锁,任何SELECT/INSERT/UPDATE/DELETE都会被阻塞 - 哪怕只是把
varchar(255)改成varchar(1024),只要涉及长度头升级(单字节→双字节),5.7 就无法就地改,必须重建
为什么SHOW PROCESSLIST里全是Waiting for table metadata lock
这不是锁住了数据,而是卡在了“抢锁”阶段:DDL 必须等目标表上所有 MDL_SHARED 锁释放,才能拿到 MDL_EXCLUSIVE 锁。而 MDL_SHARED 锁由任何未提交事务持有——哪怕只是一个 SELECT * FROM t WHERE id = 1 FOR UPDATE 没提交,或一个 Sleep 连接长时间没关闭。
-
SHOW FULL PROCESSLIST中看到Command = Sleep、Time > 300、Info = NULL的线程,大概率就是持锁者 -
information_schema.INNODB_TRX里duration_sec超过 60 秒的活跃事务,要优先排查 - 注意:
SHOW OPEN TABLES WHERE In_use > 0对 MDL 锁无效,它只反映显式LOCK TABLES或缓存引用
ALGORITHM=INPLACE + LOCK=NONE 在5.7里到底起不起作用
起作用,但非常脆弱:它只降低锁强度,不消除锁;且 MySQL 5.7 在判定不可就地执行时,**不会静默降级为拷贝模式,而是直接报错退出**,而不是继续执行。
-
LOCK=NONE表示允许读写并发,但仅限于真正支持就地修改的操作类型;一旦需要重建,就会拒绝执行并提示ALGORITHM=INPLACE is not supported - 务必先用
EXPLAIN FORMAT=JSON查看执行计划,确认"alter_algorithm": "inplace"和"lock": "none"同时出现,否则别信参数 - 即使显示
inplace,末尾索引构建、元数据切换阶段仍需短暂加锁,高并发下可能引发瞬时堆积
为什么pt-online-schema-change是更可靠的选择
它彻底绕开 MySQL 的 MDL 锁机制:不碰原表结构,而是新建影子表、用触发器捕获增量变更、最后原子切换表名。整个过程对原表只有轻量写入,业务读写几乎无感。
- 适用前提:原表必须有主键或唯一非空索引;不能已有触发器;主从延迟需可控
- 执行前必须加
--dry-run和--print,重点核对它生成的RENAME语句和触发器逻辑 - 切记:不要只在从库跑
pt-osc再手动切主从——DDL 不会自动复制,会导致主从表结构不一致
真正难的从来不是“怎么加个字段”,而是判断这次变更会不会触发重建、有没有长事务挡路、以及要不要为千万级表多留出 8 小时窗口——这些细节不提前验证,ALTER TABLE 就是一颗定时炸弹。











