应查INFORMATION_SCHEMA.INNODB_TRX,重点看trx_started是否超60秒及trx_mysql_thread_id,而非依赖SHOW PROCESSLIST或trx_state='RUNNING';KILL后需验证该thread_id是否消失且DDL状态变为altering table。

如何识别真正阻塞DDL的长事务
执行 KILL 前必须准确定位“谁在卡DDL”,不能只看 SHOW PROCESSLIST。DDL线程常显示为 Waiting for table metadata lock,但持有锁的线程可能早已进入 Sleep 状态,COMMAND 和 STATE 都不可靠。
必须查 INFORMATION_SCHEMA.INNODB_TRX,重点关注:
-
trx_started时间戳 —— 超过 60 秒未更新,基本就是元数据锁持有者 -
trx_mysql_thread_id—— 对应PROCESSLIST.ID,用于后续KILL - 不要依赖
trx_state = 'RUNNING',它只表示事务未提交,不反映活跃度
为什么 KILL 后 DDL 还不继续
常见错觉是“KILL了就完事”,但实际中 DDL 可能仍卡住,原因有二:
- 被杀线程只是释放了 MDL(元数据锁),但事务回滚本身需要时间,尤其当它已修改大量行时;回滚期间仍持有部分锁,新 DDL 无法获取完整 MDL
- 存在多个并发长事务,只杀了一个,其他仍在 hold 锁;需用
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX ORDER BY trx_started排查全部老事务
验证是否真释放:KILL 后立刻再查 INFORMATION_SCHEMA.INNODB_TRX,若原 trx_mysql_thread_id 消失,且 DDL 线程状态从 Waiting for table metadata lock 变为 altering table,才算成功解堵。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
ALTER TABLE 被阻塞时能否直接 KILL DDL 自身
可以,但要清楚后果:
-
KILL QUERY thread_id终止 DDL 执行,但已做的变更(如临时表创建、部分数据拷贝)不会自动清理,可能残留临时文件或半成品表结构 -
KILL CONNECTION thread_id更彻底,会断开连接并触发回滚,但对正在重建表的ALGORITHM=COPY操作,回滚耗时可能远超原 DDL - MySQL 8.0 的原子 DDL 保证了 DDL 失败后元数据一致,但不承诺物理层完全无痕;建议事后检查
information_schema.innodb_tables和磁盘上是否有#sql-*临时文件
如何避免下次再被慢DDL卡住
预防比急救更重要,关键动作要前置:
- 上线前确认表是否支持
ALGORITHM=INSTANT:查ROW_FORMAT是否为DYNAMIC,禁用FULLTEXT索引,避免多子句合并 ALTER(如同时加列+建索引) - 对万级以上的表,DDL 必须走低峰期 +
LOCK=NONE显式声明,并用SELECT COUNT(*)和SELECT * FROM t LIMIT 1快速验证是否真走 instant - 监控层接入
INFORMATION_SCHEMA.INNODB_TRX,对trx_started超过 30 秒的事务自动告警,而不是等 DDL 报错才响应
真正麻烦的不是“怎么杀”,而是“为什么没提前发现那个睡着却锁着表的事务”。

















