想必玩过mysql的人对Waiting for table metadata lock肯定不会陌生,一般都是进行alter操作时被堵住了,导致了我们在show processlist 时,看到线程的状态是在等metadata lock。本文会对mysql 的metadata lock做一个小小的总结,希望对大家有所帮助。
MDL是在5.5才引入到mysql,之前也有类似保护元数据的机制,只是没有
明确提出MDL概念而已。但是5.5之前版本(比如5.1)与5.5之后版本在保护元数据这块有一个显著的不同点是,5.1对于元数据的保护是语句级别的,5.5对于metadata的保护是事务级别的。所谓语句级别,即语句执行完成后,无论事务是否提交或回滚,其表结构可以被其他会话更新;而事务级别则是在事务结束后才释放MDL。
引入MDL后,主要解决了2个问题,一个是事务隔离问题,比如在可重复隔离级别下,会话A在2次查询期间,会话B对表结构做了修改,两次查询结果就会不一致,无法满足可重复读的要求;另外一个是数据复制的问题,比如会话A执行了多条更新语句期间,另外一个会话B做了表结构变更并且先提交,就会导致slave在重做时,先重做alter,再重做update时就会出现复制错误的现象。
5.5以后,什么情况下会碰到MDL锁,我结合实际情况举3个会出现MDL的场景,来分析MDL加锁时机。下文的.测试都是以mysql 5.5这个版本为基准,没有考虑到online ddl,下一篇博文会详细介绍5.6的online ddl。
1.大查询或mysqldump导致alter等待MDL
时间点 | 会话A | 会话B | 会话C |
1 | Select count(*) from t; | ||
2 | alter table t add column c3 int;阻塞 | ||
3 | Show processlist; B:Waiting for table metadata lock | ||
4 | A:执行完毕 | ||
5 | Show processlist; B:copy to tmp table | ||
6 | B:继续执行 | ||
7 | Select count(*) from t; | ||
8 | Show processlist; A: Sending data B: copy to tmp table | ||
9 | A:执行完毕 |
表1