最近遇到一个案例,不少查询被阻塞没有返回结果,使用show processlist查看,发现很多MySQL线程处于Waiting for table flush状态,查询语句一直被阻塞,只能经过Kill进程来解决。那么咱们先来看看Waiting for table flush的官方解释:https://dev.mysql.com/doc/refman/5.6/en/general-thread-states.htmlphp
Waiting for table flushhtml
The thread is executing FLUSH TABLES and is waiting for all threads to close their tables, or the thread got a notification that the underlying structure for a table has changed and it needs to reopen the table to get the new structure. However, to reopen the table, it must wait until all other threads have closed the table in question.mysql
This notification takes place if another thread has used FLUSH TABLES or one of the following statements on the table in question: FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE, or OPTIMIZE TABLE.sql
那么咱们接下来模拟一下线程处于Waiting for table flush状态的状况,如所示:数据库
在第一个会话链接(connection id=13)中,咱们使用lock table 锁定表test。测试
1ui |
|
1spa |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
在第二个会话链接(connection id=17)中,咱们执行flush table 或 flush table test 皆可。此时你会发现flush table处于阻塞状态。
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
在第三个会话/链接中,当你切换到MyDB时,就会提示“You can turn off this feature to get a quicker startup with -A” ,此时处于阻塞状态。此时你退出会话,使用参数-A登陆数据库后,你若是查询test表,就会处于阻塞状态(固然查询其它表不会被阻塞)。以下所示:
mysql> use MyDB;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
mysql> use MyDB;
Database changed
mysql> select * from test;
在第四个会话/链接,咱们用show processlist查看到当前数据库全部链接线程状态,你会看到1七、18都处于Waiting for table flush的状态。以下截图所示:
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
|
注意:咱们须要Kill线程13, Kill掉线程17是解决不了问题的。
生产环境中,不少时候可能不是lock table read引发的阻塞,而是因为慢查询,致使flush table一直没法关闭该表而一直处于等待状态,例以下面测试案例中,我使用同一张大表作笛卡尔积模拟一个慢查询,其它操做相同,以下所示,你会看到一样产生了Waiting for table flush
mysql> SELECT T.* FROM TEST1 T, TEST1 L;
另外,网上有个案例,mysqldump备份时,若是没有使用参数—single-transaction 或因为同时使用了flush-logs与—single-transaction两个参数也可能引发这样的等待场景,这个两个参数放在一块儿,会在开始dump数据以前先执行一个FLUSH TABLES操做。
解决方案:
出现Waiting for table flush时,咱们通常须要找到那些表被lock住或那些慢查询致使flush table一直在等待而没法关闭该表。而后Kill掉对应的线程便可,可是如何精准定位是一个挑战,尤为是生产环境,你使用show processlist会看到大量的线程。让你眼花缭乱的,怎么一会儿定位问题呢?
对于慢查询引发的其它线程处于Waiting for table flush状态的情形:
能够查看show processlist中Time值很大的线程。而后甄别确认后Kill掉,如上截图所示,会话链接14就是引发阻塞的源头SQL。有种规律就是这个线程的Time列值一定比被阻塞的线程要高。这个就能过滤不少记录。
对于lock table read引发的其它线程处于Waiting for table flush状态的情形:
对于实验中使用lock table read这种状况,这种会话可能处于Sleep状态,并且它也不会出如今show engine innodb status \G命令的输出信息中。 即便show open tables where in_use >=1;能找到是那张表被lock住了,可是没法定位到具体的线程(链接),其实这个是一个头痛的问题。可是inntop这款利器就能够定位到,以下所示,线程17锁住了表test,在innotop里面就能定位到是线程17。所谓工欲善其事必先利其器!
另外,在官方文档中ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE, or OPTIMIZE TABLE都能引发这类等待,下面也作了一些简单测试,以下所示:
Waiting for table flush的另一个场景
会话链接(connection id=18)执行下面SQL语句,模拟一个慢查询SQL
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
会话链接(connection id=6)执行下面SQL语句,分析表test
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
会话链接(connection id=8)执行下面SQL语句
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
查看线程的状态,你会发现被阻塞的会话处于 Waiting for table flush状态。 由于当对表作了ANALYZE TABLE后,后台针对该表的查询须要等待,由于MySQL已经检测到该表内部变化,须要使用FLUSH TABLE关闭而后从新打开该表,因此当你查询该表时,就会处于 Waiting for table flush
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
Waiting for table metadata lock
会话链接(connection id=17)执行下面SQL语句,模拟一个慢查询SQL
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
会话链接(connection id=6)执行下面SQL语句, 修改表结构操做
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
会话链接(connection id=8)执行下面SQL语句,查询表test
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
查看线程的状态,你会发现被阻塞的会话处于 Waiting for table metadata lock状态。
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
以上就是MySQL线程处于Waiting for table flush的分析的详细内容,更多请关注php中文网其它相关文章!