先查长时间未提交事务,再KILL持锁连接;因MDL锁由未结束事务或Sleep连接持有,需通过INNODB_TRX定位duration_sec超60秒的事务并终止,同时修复应用连接泄漏。

ALTER TABLE 卡在 Waiting for table metadata lock 怎么办
这不是表数据锁,而是元数据锁(MDL),只要有个长事务或 Sleep 连接没释放表引用,ALTER TABLE 就会一直等。它不看你用的是 InnoDB 还是 MyISAM,也不管有没有索引——只要目标表被任何未结束事务“碰过”,DDL 就会被阻塞。
常见现象:SHOW FULL PROCESSLIST 里能看到状态是 Waiting for table metadata lock,同时有若干 Command = Sleep、Time > 300、Info = NULL 的线程。这些就是罪魁祸首。
- 别急着 KILL 所有 Sleep 连接,先查
information_schema.INNODB_TRX确认哪些事务真正持锁且长时间未提交 - 重点关注
trx_started和duration_sec字段,超过 60 秒的活跃事务要优先处理 - 如果确认是应用侧连接泄漏(比如没 close 数据库连接),需同步修复代码,否则下次还会复现
MySQL 5.6+ 的 Online DDL 能否避免锁表
能,但不是所有 ALTER TABLE 操作都支持无锁。是否加锁、加什么锁,取决于操作类型和 MySQL 版本。例如:
-
ADD COLUMN在末尾添加列:MySQL 5.6+ 默认ALGORITHM=INPLACE,只加 MDL 锁,不阻塞 DML(但仍有短暂排他期) -
MODIFY COLUMN改类型或长度:可能触发COPY算法,全表重建 → 长时间写锁 -
DROP INDEX或ADD INDEX:InnoDB 支持INPLACE,但若索引字段没走索引扫描(如 WHERE 条件没命中索引),仍可能升级为表锁
强制指定算法:加 ALGORITHM=INPLACE, LOCK=NONE;但如果 MySQL 判定不可行,会直接报错,而不是静默降级。
pt-online-schema-change 为什么比原生命令更稳
它绕开了 MDL 锁机制本身:不直接改原表,而是新建影子表、同步数据、交换表名。整个过程对原表只有触发器级别的轻量写入,读写基本不受影响。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 适用场景:大表(千万级以上)、不能停服、主从延迟敏感的线上环境
- 注意点:
pt-osc依赖触发器,所以原表不能已有触发器;且要求主键或唯一非空索引存在,否则无法增量同步 - 执行前务必加
--dry-run和--print看它准备做什么,尤其注意它生成的RENAME语句是否符合你预期 - 不要在从库上单独跑
pt-osc再切主从——DDL 不会自动复制到主库,容易导致主从结构不一致
为什么 SHOW OPEN TABLES WHERE In_use > 0 有时看不到问题表
因为 In_use > 0 只反映当前被显式锁定(如 LOCK TABLES ... WRITE)或正被缓存使用的表,而 MDL 锁不在此列。元数据锁由服务器层管理,不体现在表缓存计数中。
真正有效的排查顺序是:
- 第一步:
SHOW FULL PROCESSLIST找Waiting for table metadata lock+ 长时间Sleep线程 - 第二步:
SELECT * FROM information_schema.INNODB_TRX ORDER BY trx_started定位未提交事务 - 第三步:
SELECT * FROM information_schema.INNODB_LOCK_WAITS看谁在等谁(MySQL 5.7+)
别依赖 SHOW OPEN TABLES 做 MDL 诊断,它会漏掉最典型的持锁场景。










