在 MySQL 5.7 中,元数据锁(MDL, Metadata Lock) 机制用于确保数据一致性,但如果处理不当,可能会导致长时间阻塞,影响数据库的并发性能。


MDL 锁的影响

任何 读取写入 操作都会获取 MDL 锁,以防止表结构在操作过程中发生变更。例如,在 SELECT 查询执行时,不能对表进行 ALTER 操作,否则会出现等待现象。

假设以下事务按顺序执行:

1.事务 A 执行:

SELECT SLEEP(3600), id FROM sbtest1 LIMIT 10;

由于 SLEEP(3600) 使查询持续 1 小时,MDL 读锁 也会保持 1 小时。


2.事务 B 试图修改表结构:

ALTER TABLE sbtest1 ADD COLUMN age INT;

由于 ALTER TABLE 需要 获取 MDL 写锁,但事务 A 未释放 MDL 读锁,事务 B 只能进入 Waiting for table metadata lock 状态,一直等待事务 A 结束。


3.事务 C 执行普通查询:

SELECT * FROM sbtest1 LIMIT 10;

由于事务 B 未能获取 MDL 写锁,事务 C 也会等待事务 B 释放锁,进入 Waiting for table metadata lock 状态,造成 连锁阻塞


优化方案:调整 lock_wait_timeout

MySQL 提供了 lock_wait_timeout 参数,控制 MDL 锁的等待时间。默认值可能长达 1 年,容易导致长时间阻塞。


建议调整此参数,例如设置为 3~10 秒,让超时的 DDL 语句自动终止,避免影响后续事务:

SET GLOBAL lock_wait_timeout = 5;

这样,当事务 B 在 5 秒内无法获取 MDL 锁,会直接报错(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)而 不会一直等待,从而防止事务 C 也陷入等待状态,提高数据库的可用性。