MySQL线程处于Waiting for table flush的分析
2017-08-18 17:22
183 查看
转自http://www.cnblogs.com/kerrycode/p/7388968.html
最近遇到一个案例,很多查询被阻塞没有返回结果,使用showprocesslist查看,发现不少MySQL线程处于Waitingfortableflush状态,查询语句一直被阻塞,只能通过Kill进程来解决。那么我们先来看看Waitingfortableflush的官方解释:https://dev.mysql.com/doc/refman/5.6/en/general-thread-states.html
Waitingfortableflush
ThethreadisexecutingFLUSHTABLESandiswaitingforallthreadstoclosetheirtables,orthethreadgotanotificationthattheunderlyingstructureforatablehaschangedanditneedstoreopenthetabletogetthenewstructure.However,toreopenthetable,itmustwaituntilallotherthreadshaveclosedthetableinquestion.
ThisnotificationtakesplaceifanotherthreadhasusedFLUSHTABLESoroneofthefollowingstatementsonthetableinquestion:FLUSHTABLEStbl_name,ALTERTABLE,RENAMETABLE,REPAIRTABLE,ANALYZETABLE,orOPTIMIZETABLE.
那么我们接下来模拟一下线程处于Waitingfortableflush状态的情况,如所示:
在第一个会话连接(connectionid=13)中,我们使用locktable锁定表test。
在第二个会话连接(connectionid=17)中,我们执行flushtable或flushtabletest皆可。此时你会发现flushtable处于阻塞状态。
在第三个会话/连接中,当你切换到MyDB时,就会提示“Youcanturnoffthisfeaturetogetaquickerstartupwith-A”,此时处于阻塞状态。此时你退出会话,使用参数-A登录数据库后,你如果查询test表,就会处于阻塞状态(当然查询其它表不会被阻塞)。如下所示:
mysql>useMyDB;
Readingtableinformationforcompletionoftableandcolumnnames
Youcanturnoffthisfeaturetogetaquickerstartupwith-A
mysql>useMyDB;
Databasechanged
mysql>select*fromtest;
在第四个会话/连接,我们用showprocesslist查看到当前数据库所有连接线程状态,你会看到17、18都处于Waitingfortableflush的状态。如下截图所示:
|
注意:我们需要Kill线程13,Kill掉线程17是解决不了问题的。
生产环境中,很多时候可能不是locktableread引起的阻塞,而是由于慢查询,导致flushtable一直无法关闭该表而一直处于等待状态,例如下面测试案例中,我使用同一张大表做笛卡尔积模拟一个慢查询,其它操作相同,如下所示,你会看到同样产生了Waitingfortableflush
mysql>SELECTT.*FROMTEST1T,TEST1L;
另外,网上有个案例,mysqldump备份时,如果没有使用参数—single-transaction或由于同时使用了flush-logs与—single-transaction两个参数也可能引起这样的等待场景,这个两个参数放在一起,会在开始dump数据之前先执行一个FLUSHTABLES操作。
解决方案:
出现Waitingfortableflush时,我们一般需要找到那些表被lock住或那些慢查询导致flushtable一直在等待而无法关闭该表。然后Kill掉对应的线程即可,但是如何精准定位是一个挑战,尤其是生产环境,你使用showprocesslist会看到大量的线程。让你眼花缭乱的,怎么一下子定位问题呢?
对于慢查询引起的其它线程处于Waitingfortableflush状态的情形:
可以查看showprocesslist中Time值很大的线程。然后甄别确认后Kill掉,如上截图所示,会话连接14就是引起阻塞的源头SQL。有种规律就是这个线程的Time列值必定比被阻塞的线程要高。这个就能过滤很多记录。
对于locktableread引起的其它线程处于Waitingfortableflush状态的情形:
对于实验中使用locktableread这种情况,这种会话可能处于Sleep状态,而且它也不会出现在showengineinnodbstatus\G命令的输出信息中。即使showopentableswherein_use>=1;能找到是那张表被lock住了,但是无法定位到具体的线程(连接),其实这个是一个头痛的问题。但是inntop这款利器就可以定位到,如下所示,线程17锁住了表test,在innotop里面就能定位到是线程17。所谓工欲善其事必先利其器!
另外,在官方文档中ALTERTABLE,RENAMETABLE,REPAIRTABLE,ANALYZETABLE,orOPTIMIZETABLE都能引起这类等待,下面也做了一些简单测试,如下所示:
Waitingfortableflush的另外一个场景
会话连接(connectionid=18)执行下面SQL语句,模拟一个慢查询SQL
会话连接(connectionid=6)执行下面SQL语句,分析表test
会话连接(connectionid=8)执行下面SQL语句
查看线程的状态,你会发现被阻塞的会话处于Waitingfortableflush状态。因为当对表做了ANALYZETABLE后,后台针对该表的查询需要等待,因为MySQL已经检测到该表内部变化,需要使用FLUSHTABLE关闭然后重新打开该表,所以当你查询该表时,就会处于Waitingfortableflush
Waitingfortablemetadatalock
会话连接(connectionid=17)执行下面SQL语句,模拟一个慢查询SQL
会话连接(connectionid=6)执行下面SQL语句,修改表结构操作
会话连接(connectionid=8)执行下面SQL语句,查询表test
查看线程的状态,你会发现被阻塞的会话处于Waitingfortablemetadatalock状态。
参考资料:
https://www.percona.com/blog/2013/02/27/mysql-optimizer-analyze-table-and-waiting-for-table-flush/
http://www.cnblogs.com/jackhub/p/3841004.html
http://myrock.github.io/2014/11/20/mysql-waiting-for-table-flush/
http://mysql.taobao.org/monthly/2016/03/10/
最近遇到一个案例,很多查询被阻塞没有返回结果,使用showprocesslist查看,发现不少MySQL线程处于Waitingfortableflush状态,查询语句一直被阻塞,只能通过Kill进程来解决。那么我们先来看看Waitingfortableflush的官方解释:https://dev.mysql.com/doc/refman/5.6/en/general-thread-states.html
Waitingfortableflush
ThethreadisexecutingFLUSHTABLESandiswaitingforallthreadstoclosetheirtables,orthethreadgotanotificationthattheunderlyingstructureforatablehaschangedanditneedstoreopenthetabletogetthenewstructure.However,toreopenthetable,itmustwaituntilallotherthreadshaveclosedthetableinquestion.
ThisnotificationtakesplaceifanotherthreadhasusedFLUSHTABLESoroneofthefollowingstatementsonthetableinquestion:FLUSHTABLEStbl_name,ALTERTABLE,RENAMETABLE,REPAIRTABLE,ANALYZETABLE,orOPTIMIZETABLE.
那么我们接下来模拟一下线程处于Waitingfortableflush状态的情况,如所示:
在第一个会话连接(connectionid=13)中,我们使用locktable锁定表test。
mysql>useMyDB;
Databasechanged
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|13|
+-----------------+
1rowinset(0.00sec)
mysql>locktabletestread;
QueryOK,0rowsaffected(0.00sec)
mysql>
在第二个会话连接(connectionid=17)中,我们执行flushtable或flushtabletest皆可。此时你会发现flushtable处于阻塞状态。
mysql>useMyDB;
Readingtableinformationforcompletionoftableandcolumnnames
Youcanturnoffthisfeaturetogetaquickerstartupwith-A
Databasechanged
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|17|
+-----------------+
1rowinset(0.00sec)
mysql>flushtabletest;
在第三个会话/连接中,当你切换到MyDB时,就会提示“Youcanturnoffthisfeaturetogetaquickerstartupwith-A”,此时处于阻塞状态。此时你退出会话,使用参数-A登录数据库后,你如果查询test表,就会处于阻塞状态(当然查询其它表不会被阻塞)。如下所示:
mysql>useMyDB;
Readingtableinformationforcompletionoftableandcolumnnames
Youcanturnoffthisfeaturetogetaquickerstartupwith-A
mysql>useMyDB;
Databasechanged
mysql>select*fromtest;
在第四个会话/连接,我们用showprocesslist查看到当前数据库所有连接线程状态,你会看到17、18都处于Waitingfortableflush的状态。如下截图所示:
mysql>showprocesslist;
+----+------+-----------+------+---------+------+-------------------------+--------------------+
|Id|User|Host|db|Command|Time|State|Info|
+----+------+-----------+------+---------+------+-------------------------+--------------------+
|13|root|localhost|MyDB|Sleep|90||NULL|
|14|root|localhost|NULL|Query|0|init|showprocesslist|
|17|root|localhost|MyDB|Query|52|Waitingfortableflush|flushtabletest|
|18|root|localhost|MyDB|Query|9|Waitingfortableflush|select*fromtest|
+----+------+-----------+------+---------+------+-------------------------+--------------------+
4rowsinset(0.00sec)
mysql>
mysql>showprocesslist;
+----+------+-----------+------+---------+------+-------------------------+--------------------+
|Id|User|Host|db|Command|Time|State|Info|
+----+------+-----------+------+---------+------+-------------------------+--------------------+
|13|root|localhost|MyDB|Sleep|90||NULL|
|14|root|localhost|NULL|Query|0|init|showprocesslist|
|17|root|localhost|MyDB|Query|52|Waitingfortableflush|flushtabletest|
|18|root|localhost|MyDB|Query|9|Waitingfortableflush|select*fromtest|
+----+------+-----------+------+---------+------+-------------------------+--------------------+
4rowsinset(0.00sec)
mysql>
mysql>
mysql>
mysql>
mysql>showopentableswherein_use>=1;
+----------+-------+--------+-------------+
|Database|Table|In_use|Name_locked|
+----------+-------+--------+-------------+
|MyDB|test|1|0|
+----------+-------+--------+-------------+
1rowinset(0.00sec)
mysql>kill17;
QueryOK,0rowsaffected(0.00sec)
mysql>showprocesslist;
+----+------+-----------+------+---------+------+-------------------------+--------------------+
|Id|User|Host|db|Command|Time|State|Info|
+----+------+-----------+------+---------+------+-------------------------+--------------------+
|13|root|localhost|MyDB|Sleep|442||NULL|
|14|root|localhost|NULL|Query|0|init|showprocesslist|
|18|root|localhost|MyDB|Query|361|Waitingfortableflush|select*fromtest|
+----+------+-----------+------+---------+------+-------------------------+--------------------+
3rowsinset(0.00sec)
mysql>kill13;
QueryOK,0rowsaffected(0.00sec)
mysql>showprocesslist;
+----+------+-----------+------+---------+------+-------+------------------+
|Id|User|Host|db|Command|Time|State|Info|
+----+------+-----------+------+---------+------+-------+------------------+
|14|root|localhost|NULL|Query|0|init|showprocesslist|
|18|root|localhost|MyDB|Sleep|427||NULL|
+----+------+-----------+------+---------+------+-------+------------------+
2rowsinset(0.00sec)
mysql>
|
注意:我们需要Kill线程13,Kill掉线程17是解决不了问题的。
生产环境中,很多时候可能不是locktableread引起的阻塞,而是由于慢查询,导致flushtable一直无法关闭该表而一直处于等待状态,例如下面测试案例中,我使用同一张大表做笛卡尔积模拟一个慢查询,其它操作相同,如下所示,你会看到同样产生了Waitingfortableflush
mysql>SELECTT.*FROMTEST1T,TEST1L;
另外,网上有个案例,mysqldump备份时,如果没有使用参数—single-transaction或由于同时使用了flush-logs与—single-transaction两个参数也可能引起这样的等待场景,这个两个参数放在一起,会在开始dump数据之前先执行一个FLUSHTABLES操作。
解决方案:
出现Waitingfortableflush时,我们一般需要找到那些表被lock住或那些慢查询导致flushtable一直在等待而无法关闭该表。然后Kill掉对应的线程即可,但是如何精准定位是一个挑战,尤其是生产环境,你使用showprocesslist会看到大量的线程。让你眼花缭乱的,怎么一下子定位问题呢?
对于慢查询引起的其它线程处于Waitingfortableflush状态的情形:
可以查看showprocesslist中Time值很大的线程。然后甄别确认后Kill掉,如上截图所示,会话连接14就是引起阻塞的源头SQL。有种规律就是这个线程的Time列值必定比被阻塞的线程要高。这个就能过滤很多记录。
对于locktableread引起的其它线程处于Waitingfortableflush状态的情形:
对于实验中使用locktableread这种情况,这种会话可能处于Sleep状态,而且它也不会出现在showengineinnodbstatus\G命令的输出信息中。即使showopentableswherein_use>=1;能找到是那张表被lock住了,但是无法定位到具体的线程(连接),其实这个是一个头痛的问题。但是inntop这款利器就可以定位到,如下所示,线程17锁住了表test,在innotop里面就能定位到是线程17。所谓工欲善其事必先利其器!
另外,在官方文档中ALTERTABLE,RENAMETABLE,REPAIRTABLE,ANALYZETABLE,orOPTIMIZETABLE都能引起这类等待,下面也做了一些简单测试,如下所示:
Waitingfortableflush的另外一个场景
会话连接(connectionid=18)执行下面SQL语句,模拟一个慢查询SQL
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|18|
+-----------------+
1rowinset(0.00sec)
mysql>selectname,sleep(64)fromtest;
会话连接(connectionid=6)执行下面SQL语句,分析表test
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|6|
+-----------------+
1rowinset(0.00sec)
mysql>analyzetabletest;
+-----------+---------+----------+----------+
|Table|Op|Msg_type|Msg_text|
+-----------+---------+----------+----------+
|MyDB.test|analyze|status|OK|
+-----------+---------+----------+----------+
1rowinset(0.04sec)
mysql>
会话连接(connectionid=8)执行下面SQL语句
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|8|
+-----------------+
1rowinset(0.00sec)
mysql>select*fromtest;
查看线程的状态,你会发现被阻塞的会话处于Waitingfortableflush状态。因为当对表做了ANALYZETABLE后,后台针对该表的查询需要等待,因为MySQL已经检测到该表内部变化,需要使用FLUSHTABLE关闭然后重新打开该表,所以当你查询该表时,就会处于Waitingfortableflush
mysql>showprocesslist;
+----+------+-----------+------+---------+------+-------------------------+----------------------------------+
|Id|User|Host|db|Command|Time|State|Info|
+----+------+-----------+------+---------+------+-------------------------+----------------------------------+
|6|root|localhost|MyDB|Sleep|22||NULL|
|8|root|localhost|MyDB|Query|14|Waitingfortableflush|select*fromtest|
|15|root|localhost|NULL|Sleep|3||NULL|
|16|root|localhost|NULL|Query|0|init|showprocesslist|
|18|root|localhost|MyDB|Query|46|Usersleep|selectname,sleep(64)fromtest|
+----+------+-----------+------+---------+------+-------------------------+----------------------------------+
5rowsinset(0.00sec)
mysql>
Waitingfortablemetadatalock
会话连接(connectionid=17)执行下面SQL语句,模拟一个慢查询SQL
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|17|
+-----------------+
1rowinset(0.00sec)
mysql>selectname,sleep(100)fromtest;
会话连接(connectionid=6)执行下面SQL语句,修改表结构操作
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|6|
+-----------------+
1rowinset(0.00sec)
mysql>altertabletestaddtnamevarchar(10);//renametabletesttokkk同样会引起Waitingfortablemetadatalock
会话连接(connectionid=8)执行下面SQL语句,查询表test
mysql>selectconnection_id();
+-----------------+
|connection_id()|
+-----------------+
|8|
+-----------------+
1rowinset(0.00sec)
mysql>select*fromtest;
查看线程的状态,你会发现被阻塞的会话处于Waitingfortablemetadatalock状态。
mysql>showprocesslist;
+----+------+-----------+------+---------+------+---------------------------------+----------------------------------------+
|Id|User|Host|db|Command|Time|State|Info|
+----+------+-----------+------+---------+------+---------------------------------+----------------------------------------+
|6|root|localhost|MyDB|Query|19|Waitingfortablemetadatalock|altertabletestaddtnamevarchar(10)|
|8|root|localhost|MyDB|Query|6|Waitingfortablemetadatalock|select*fromtest|
|15|root|localhost|NULL|Sleep|8||NULL|
|16|root|localhost|NULL|Query|0|init|showprocesslist|
|17|root|localhost|MyDB|Query|55|Usersleep|selectname,sleep(100)fromtest|
+----+------+-----------+------+---------+------+---------------------------------+----------------------------------------+
5rowsinset(0.00sec)
mysql>
参考资料:
相关文章推荐
- MySQL线程处于Waiting for table flush的分析
- MySQL线程处于Waiting for table flush的分析
- 再论mysql线程出现Waiting for table flush被hang住问题
- 【转】【MySql】Waiting for table metadata lock原因分析
- MySQL出现Waiting for table metadata lock的场景浅析
- MySQL出现Waiting for table metadata lock的原因以及解决方法
- mysql Waiting for table level lock
- mysql5.7.10 出现waiting for table metadata lock
- MySQL出现Waiting for table metadata lock的原因以及解决方法
- MySQL出现Waiting for table metadata lock的原因以及解决方法
- MySQL出现Waiting for table metadata lock的场景浅析
- mysql出现Waiting for table metadata lock的原因及解决方案
- mysql5.7.10 出现waiting for table metadata lock
- mysql出现Waiting for table metadata lock的原因及解决方案
- MySQL出现Waiting for table metadata lock的场景浅析
- MySQL drop空表时处于Waiting for table metadata lock状态,解决办法
- alter table Waiting for table metadata lock, mysql 5.6 看不到锁在哪儿
- Waiting for table flush 阻塞查询的问题
- alter table锁表,MySQL出现Waiting for table metadata lock的场景浅析及解决方案
- MySQL出现Waiting for table metadata lock的原因以及解决方法