[[toc]]
适用范围
mysql 5.6+
问题概述
业务跑批过程当中,反应超时。通过等待事件查看,发现程序一直在等待元数据锁“Waiting for table metadata lock” ,而我们通过show processlist在该表上并没有查看到相应的操作。
问题原因
路批脚本中有alter table 增加分区的句语,需要获取“ metadata lock”。而所对应的表同时有其它业务DML操作后未提交处理,其它业务是运行在显式的事务中的。 这很可能是因为在一个显式的事务中,对TableA进行了一个失败的操作,这时事务没有开始,但是失败语句获取到的锁依然有效,没有释放。也是我们场景三情况。
解决方案
针对 “Waiting for table metadata lock” 不同场景,整理了以下三种不同的解决方案。
场景一: 长事物运行,阻塞DDL,继而阻塞所有同表的后续操作.
通过show processlist可以看到TableA上有正在进行的操作(包括读),此时alter table语句无法获取到metadata 独占锁,会进行等待。
一般alter table的操作过程中,在after create步骤会获取metadata 独占锁,当进行到altering table的过程时(通常是最花时间的步骤),对该表的读写都可以正常进行,这就是online ddl的表现,并不会像之前在整个alter table过程中阻塞写入。
解决办法:通过show processlist 查看并确认, kill掉DDL所在的session.
场景二:未提交事物,阻塞DDL,继而阻塞所有同表的后续操作
通过show processlist看不到TableA上有任何操作,但实际上存在有未提交的事务,可以在 information_schema.innodb_trx中查看到。在事务没有完成之前,TableA上的锁不会释放,alter table同样获取不到metadata的独占锁。
解决办法:通过 select * from information_schema.innodb_trx\G, 找到未提交事物的sid, 然后 kill 掉,让其回滚。
场景三:未提交事物,阻塞DDL,通过show processlist看不到TableA上有任何操作。
通过show processlist看不到TableA上有任何操作,在information_schema.innodb_trx中也没有任何进行中的事务。这很可能是因为在一个显式的事务中,对TableA进行了一个失败的操作(比如查询了一个不存在的字段),这时事务没有开始,但是失败语句获取到的锁依然有效,没有释放。从performance_schema.events_statements_current表中可以查到失败的语句。
解决办法:通过performance_schema.events_statements_current找到其sid, kill 掉该session. 也可以 kill 掉DDL所在的session.
参考文档
http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html