真正卡住ddl的是“睡着但没提交”的长事务,需查information_schema.innodb_trx中trx_started超120秒、trx_state='running'且short_query为空或select的记录,因其持有s mdl锁阻塞ddl。

查 information_schema.innodb_trx 看谁在“睡着但没提交”
真正卡住 DDL 的,往往不是正在跑的 SQL,而是一个早已执行完、Command 显示为 Sleep、Info 为空、但事务状态仍是 RUNNING 的连接。它不活跃,却死死攥着 S MDL 锁。
关键判断依据不是 trx_state = 'RUNNING',而是 trx_started 时间戳是否远早于当前时间——比如超过 2 分钟或 5 分钟(按业务容忍度定):
SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id, SUBSTRING_INDEX(trx_query, ' ', 4) AS short_query FROM information_schema.innodb_trx WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 120;- 如果
short_query是SELECT或空,基本可判定是“查完就走人,忘了 COMMIT” - 别只看
trx_mysql_thread_id,要拿它去反查performance_schema.threads和events_statements_current,确认该线程当前是否真在空闲
用 sys.schema_table_lock_waits 直接定位等待链
这是 MySQL 5.7+ 最省力的入口,不用拼表、不用猜关系,一行 SQL 就告诉你谁在等、谁在堵、堵了多久、堵的是哪条语句:
SELECT * FROM sys.schema_table_lock_waits;- 重点关注
waiting_pid(被卡住的线程)、blocking_pid(源头线程)、waiting_query和blocking_query - 如果
blocking_query是NULL或空,说明源头事务早已执行完毕,只是没提交——这正是最典型的“静默长事务” - 若权限受限或
sys库未启用,退而用SELECT * FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'PENDING';找出等待项,再关联OBJECT_SCHEMA和OBJECT_NAME定位具体表
别信 SHOW PROCESSLIST 的 Time 列
Time 只表示连接空闲时长,不代表事务活跃度。一个 Time = 3600 的 Sleep 连接,可能刚连上来啥都没干;而一个 Time = 5 的 Query 连接,可能正卡在锁上动弹不得。
- 必须结合
State和Info综合判断:State = 'Waiting for table metadata lock'是受害者,State = 'Executing'或State = 'copy to tmp table'才可能是 DDL 源头 - 真正要盯的是
information_schema.innodb_trx里的trx_started—— 它不会骗人,时间戳就是事务开启的真实时刻 - ORM 场景下(如 Spring
@Transactional、Djangoatomic),异常未被捕获时容易漏 rollback,这类事务在innodb_trx中也表现为RUNNING+ 老时间戳 +trx_query = NULL
KILL 前先确认它到底写了多少数据
直接 KILL <thread_id></thread_id> 会触发回滚,如果 trx_rows_modified > 0 且数值很大,回滚可能持续数分钟甚至更久,期间锁仍不释放,DDL 还是卡着。
- 先查修改量:
SELECT trx_id, trx_state, trx_isolation_level, trx_rows_modified FROM information_schema.innodb_trx WHERE trx_mysql_thread_id = ?; - 如果
trx_rows_modified = 0,大概率只是个只读事务,KILL 安全、快速 - 如果数值大,优先联系对应服务 owner,确认是否可中断;必要时考虑先暂停应用写入,再 KILL,避免回滚放大影响
- 切记:
KILL QUERY <thread_id></thread_id>没用——它只终止当前语句,事务还在,MDL 锁照旧挂着
最常被忽略的一点:哪怕只执行了一条 SELECT,只要没 COMMIT,就持续持有 S MDL 锁。这不是性能问题,是锁协议的硬性约束,无法绕过,只能靠监控和规范来防。











