DDL卡在Waiting for table metadata lock时,需通过performance_schema.events_statements_current和events_stages_current判断阶段:若EVENT_NAME为alter_table且CURRENT_STAGE=0,说明尚未获取MDL排他锁,应查GRANTED状态的metadata_locks定位长事务;若CURRENT_STAGE>0,则根据stage名称(如copy to tmp table)确认执行中瓶颈,此时不应误杀。

DDL卡在Waiting for table metadata lock,怎么确认是哪个阶段被卡住
直接看SHOW PROCESSLIST里的State字段为Waiting for table metadata lock,只能说明它在等锁,但无法区分是“还没拿到MDL排他锁”还是“拿到了MDL锁,正在执行ALTER的内部阶段(如拷表、重建索引)”。这两个阶段的处理方式完全不同:前者要杀源头事务,后者可能只是慢,不该乱KILL。
真正能定位阶段的依据是performance_schema.events_statements_current和performance_schema.events_stages_current:
- 如果
EVENT_NAME显示statement/sql/alter_table且CURRENT_STAGE = 0,说明还在等待MDL锁,尚未进入实际执行 - 如果
CURRENT_STAGE > 0,查events_stages_current中对应NESTING_EVENT_ID的EVENT_NAME,常见值有:stage/innodb/alter table end(快结束了)、stage/innodb/alter table copy to tmp table(正在拷数据)、stage/innodb/alter table insert(正在回填) - 配合
TIMER_WAIT看耗时:若某stage停留超数分钟,基本可判定是该阶段瓶颈(比如大表拷贝、二级索引重建)
为什么查INNODB_TRX找不到阻塞源,但DDL就是不往下走
因为持有MDL共享锁的会话,未必出现在INNODB_TRX里。典型场景有:
-
autocommit=0下只执行了BEGIN或SELECT,没提交也没报错,TRX_QUERY为空,但TRX_STATE = 'RUNNING'且TRX_STARTED很早 - 连接已断开但MySQL未及时回收(尤其在应用层用连接池+长空闲超时),
threads.PROCESSLIST_STATE = 'Sleep',但metadata_locks.LOCK_DURATION = 'TRANSACTION'仍为GRANTED - 显式
LOCK TABLES ... READ这类语句,不走InnoDB事务,不会出现在INNODB_TRX,但会稳稳占着MDL共享锁
必须联合查performance_schema.metadata_locks,过滤LOCK_STATUS = 'GRANTED'且LOCK_DURATION = 'TRANSACTION'的行,再通过OWNER_THREAD_ID关联threads.PROCESSLIST_ID才能准确定位。
ALGORITHM=INPLACE + LOCK=NONE生效了,为什么还是看到Waiting for table metadata lock
这个组合不是“全程无锁”,而是在特定子阶段规避锁升级。即使配置正确,以下环节仍需短暂加XMDL锁:
- DDL开始前的元数据校验阶段:检查表是否存在、字段名是否冲突、外键依赖等,必须获取XMDL
- 操作完成后的元数据刷新阶段:更新
information_schema.COLUMNS、TABLES等系统表,也要XMDL - MySQL 8.0.12+的
INSTANTADD COLUMN确实全程只加SMDL,但MODIFY COLUMN哪怕改默认值,在5.7/8.0早期仍会退化为REBUILD,触发拷表阶段的XMDL
所以看到Waiting for table metadata lock,不能直接否定ALGORITHM配置,得先用events_stages_current确认当前卡在哪一stage——如果是stage/innodb/alter table start或end,大概率就是那两个毫秒级的XMDL临界点;如果是copy to tmp table,说明已经退化,配置没生效。
从库SQL线程卡住时,如何区分是MDL阻塞还是复制延迟本身
关键看SHOW SLAVE STATUS里的两个字段:
-
Seconds_Behind_Master持续增长 → 复制延迟,可能是主库写入太快或从库IO/SQL线程跟不上 -
Seconds_Behind_Master = 0但Slave_SQL_Running_State卡在Waiting for table metadata lock→ 确认为MDL阻塞,且源头一定在从库本地(比如人为在从库开了长事务、或上一个DDL没执行完) - 注意:
Slave_SQL_Running_State显示Reading event from the relay log或Executing event时,Seconds_Behind_Master也可能为0,需结合Relay_Log_Space是否持续增大来交叉判断
最稳妥的做法是:STOP SLAVE SQL_THREAD后,立刻查performance_schema.metadata_locks,目标对象是DDL语句涉及的表,而不是主库binlog里写的任意表——从库的MDL阻塞永远只发生在它自己正在重放的那条语句上,和主库无关。


















