用心打造
VPS知识分享网站

MySQL出现Waiting for table metadata lock怎么办?先找到阻塞它的事务

执行 ALTER TABLE、建索引或修改字段时,语句长时间没有完成,进程列表显示 Waiting for table metadata lock。继续提交新的查询后,连普通读写也开始排队,网站随之变慢。

这个现象不是数据库正在慢慢修改表,而是DDL仍在等待获得对象的元数据锁。MySQL用元数据锁保护表、库、存储程序等对象的一致性;一个看似空闲但没有结束的事务,也可能让后续DDL一直等待。

元数据锁等待

先保存等待现场

先记录当前连接、等待时间和完整语句:

SHOW FULL PROCESSLIST;

重点找State为 Waiting for table metadata lock 的会话,记下连接ID、用户、来源、数据库、等待时长和SQL。不要立刻重启MySQL,否则等待链和持锁者会一起消失,事后只剩业务恢复过的表象。

还要记录故障开始时间、刚执行的发布或DDL,以及应用连接数变化。等待者通常不是根因,真正要找的是同一对象上已经获得锁却未释放的会话。

从metadata_locks区分等待与持有

MySQL 8可以读取Performance Schema中的元数据锁:

SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME,
       LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID
FROM performance_schema.metadata_locks
WHERE OBJECT_SCHEMA = 'app_db'
  AND OBJECT_NAME = 'orders';

把库名和表名换成现场对象。PENDING 表示锁请求尚未获得,GRANTED 表示已获得;需要通过对象、锁类型和线程ID建立等待关系,而不是看到任意GRANTED记录就结束会话。

元数据锁检测默认启用的版本可以直接查询。表为空或权限不足时,先确认Performance Schema配置和账号权限,不要用猜测补齐证据。

把线程ID映射到真实连接

OWNER_THREAD_ID 不是 KILL 使用的连接ID。可与线程表和语句表关联,找到实际进程:

SELECT t.THREAD_ID, t.PROCESSLIST_ID, t.PROCESSLIST_USER,
       t.PROCESSLIST_HOST, t.PROCESSLIST_TIME, t.PROCESSLIST_STATE,
       t.PROCESSLIST_INFO
FROM performance_schema.threads AS t
WHERE t.THREAD_ID IN (
  SELECT OWNER_THREAD_ID
  FROM performance_schema.metadata_locks
  WHERE OBJECT_SCHEMA = 'app_db' AND OBJECT_NAME = 'orders'
);

同时检查事务表:

SELECT trx_mysql_thread_id, trx_started, trx_state,
       trx_tables_locked, trx_rows_modified, trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;

常见持锁者是应用开启事务后长期停留、管理工具关闭窗口却没有提交,或批处理仍在访问目标表。会话显示Sleep不代表它没有未提交事务。

为什么新的普通查询也会排队

一个长事务先持有共享元数据锁,DDL随后请求排他的元数据锁并进入等待。之后到来的查询可能又排在DDL后面,于是原本只影响结构变更的问题扩散成业务请求堆积。

此时只终止等待中的DDL,可能让后续查询暂时恢复,但长事务仍然存在;只扩大连接池,则会让更多请求进入等待。必须先画出持锁者、DDL等待者和后续会话的顺序。

终止会话前先评估事务影响

最理想的处理是让持锁业务正常提交或回滚。来源明确、事务可重试时,才评估终止对应连接:

KILL CONNECTION connection_id;

不要把 OWNER_THREAD_ID 直接填入KILL,也不要批量终止所有Sleep连接。包含大量未提交修改的事务被终止后需要回滚,回滚期间资源压力仍可能很高;支付、订单等关键事务还要先确认业务幂等与重试机制。

生产环境中的DDL也应评估锁等待超时、在线DDL能力、表大小和维护窗口。显示online并不意味着完全不需要元数据锁,开始和结束阶段仍可能受并发事务影响。

从应用侧修复长期事务

锁解除只是现场恢复,根因通常在事务边界。继续检查应用是否在等待外部接口或用户操作时保持数据库事务,异常路径是否遗漏提交和回滚,连接池归还连接前是否清理事务状态。

为关键事务记录开始、提交、回滚和请求标识,并设置符合业务的事务超时。定期观察长事务和元数据锁等待,比在发布时临时KILL连接更稳妥。

旧数据库版本、连接池和业务代码同时变化时,可以在 萤光云 准备同版本数据库复现事务,也可以使用按小时计费的 LightNode 建立隔离验证环境。只复制脱敏结构和必要测试数据,不要把生产凭据或完整客户数据带入对照环境。

验收标准要覆盖下一次DDL

处理后重新读取 SHOW FULL PROCESSLISTmetadata_locksinnodb_trx,目标对象不应再存在长期PENDING记录,异常长事务已经提交、回滚或得到业务解释。

随后在维护窗口重试原DDL,记录开始、获得锁和完成时间;应用请求没有随之堆积,连接数和响应时间保持正常。最后修复应用事务边界,并通过压测或回归测试确认异常分支会正确回滚。

只让本次ALTER执行完成,还不能算关闭问题。能解释持锁来源、修复事务生命周期,并让下一次结构变更可控完成,证据链才完整。

赞(0)
未经允许不得转载;国外VPS测评网 » MySQL出现Waiting for table metadata lock怎么办?先找到阻塞它的事务
分享到