最近遇到一个案例,很多查询被阻塞没有返回结果,使用show processlist查看,发现不少MySQL线程处于Waiting for table flush状态,查询语句一直被阻塞,只能通过Kill进程来解决。那么我们先来看看Waiting for table flush的官方解释:https://dev.mysql.com/doc/refman/5.6/en/general-thread-states.html

Waiting for table flush

 

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.

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.

那么我们接下来模拟一下线程处于Waiting for table flush状态的情况,如所示:

 

在第一个会话连接(connection id=13)中,我们使用lock table 锁定表test。

mysql> use MyDB;

Database changed

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|              13 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> lock table test read;

Query OK, 0 rows affected (0.00 sec)

 

mysql> 

在第二个会话连接(connection id=17)中,我们执行flush table 或 flush table test 皆可。此时你会发现flush table处于阻塞状态。

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

 

Database changed

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|              17 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> flush table test;

在第三个会话/连接中,当你切换到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查看到当前数据库所有连接线程状态,你会看到17、18都处于Waiting for table flush的状态。如下截图所示:

mysql> show processlist;

+----+------+-----------+------+---------+------+-------------------------+--------------------+

| Id | User | Host      | db   | Command | Time | State                   | Info               |

+----+------+-----------+------+---------+------+-------------------------+--------------------+

| 13 | root | localhost | MyDB | Sleep   |   90 |                         | NULL               |

| 14 | root | localhost | NULL | Query   |    0 | init                    | show processlist   |

| 17 | root | localhost | MyDB | Query   |   52 | Waiting for table flush | flush table test   |

| 18 | root | localhost | MyDB | Query   |    9 | Waiting for table flush | select * from test |

+----+------+-----------+------+---------+------+-------------------------+--------------------+

4 rows in set (0.00 sec)

 

mysql> 

mysql> show processlist;

+----+------+-----------+------+---------+------+-------------------------+--------------------+

| Id | User | Host      | db   | Command | Time | State                   | Info               |

+----+------+-----------+------+---------+------+-------------------------+--------------------+

| 13 | root | localhost | MyDB | Sleep   |   90 |                         | NULL               |

| 14 | root | localhost | NULL | Query   |    0 | init                    | show processlist   |

| 17 | root | localhost | MyDB | Query   |   52 | Waiting for table flush | flush table test   |

| 18 | root | localhost | MyDB | Query   |    9 | Waiting for table flush | select * from test |

+----+------+-----------+------+---------+------+-------------------------+--------------------+

4 rows in set (0.00 sec)

 

mysql> 

mysql> 

mysql> 

mysql> 

mysql> show open tables where in_use >=1;

+----------+-------+--------+-------------+

| Database | Table | In_use | Name_locked |

+----------+-------+--------+-------------+

| MyDB     | test  |      1 |           0 |

+----------+-------+--------+-------------+

1 row in set (0.00 sec)

 

mysql> kill 17;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show processlist;

+----+------+-----------+------+---------+------+-------------------------+--------------------+

| Id | User | Host      | db   | Command | Time | State                   | Info               |

+----+------+-----------+------+---------+------+-------------------------+--------------------+

| 13 | root | localhost | MyDB | Sleep   |  442 |                         | NULL               |

| 14 | root | localhost | NULL | Query   |    0 | init                    | show processlist   |

| 18 | root | localhost | MyDB | Query   |  361 | Waiting for table flush | select * from test |

+----+------+-----------+------+---------+------+-------------------------+--------------------+

3 rows in set (0.00 sec)

 

mysql> kill 13;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show processlist;

+----+------+-----------+------+---------+------+-------+------------------+

| Id | User | Host      | db   | Command | Time | State | Info             |

+----+------+-----------+------+---------+------+-------+------------------+

| 14 | root | localhost | NULL | Query   |    0 | init  | show processlist |

| 18 | root | localhost | MyDB | Sleep   |  427 |       | NULL             |

+----+------+-----------+------+---------+------+-------+------------------+

2 rows in set (0.00 sec)

 

mysql> 

|

注意:我们需要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

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|              18 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> select name, sleep(64) from test;

会话连接(connection id=6)执行下面SQL语句,分析表test

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|               6 |

+-----------------+

1 row in set (0.00 sec)

mysql> analyze table test;

+-----------+---------+----------+----------+

| Table     | Op      | Msg_type | Msg_text |

+-----------+---------+----------+----------+

| MyDB.test | analyze | status   | OK       |

+-----------+---------+----------+----------+

1 row in set (0.04 sec)

 

mysql> 

会话连接(connection id=8)执行下面SQL语句

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|               8 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> select * from test;

查看线程的状态,你会发现被阻塞的会话处于 Waiting for table flush状态。 因为当对表做了ANALYZE TABLE后,后台针对该表的查询需要等待,因为MySQL已经检测到该表内部变化,需要使用FLUSH TABLE关闭然后重新打开该表,所以当你查询该表时,就会处于 Waiting for table flush

mysql> show processlist;

+----+------+-----------+------+---------+------+-------------------------+----------------------------------+

| Id | User | Host      | db   | Command | Time | State                   | Info                             |

+----+------+-----------+------+---------+------+-------------------------+----------------------------------+

|  6 | root | localhost | MyDB | Sleep   |   22 |                         | NULL                             |

|  8 | root | localhost | MyDB | Query   |   14 | Waiting for table flush | select * from test               |

| 15 | root | localhost | NULL | Sleep   |    3 |                         | NULL                             |

| 16 | root | localhost | NULL | Query   |    0 | init                    | show processlist                 |

| 18 | root | localhost | MyDB | Query   |   46 | User sleep              | select name, sleep(64) from test |

+----+------+-----------+------+---------+------+-------------------------+----------------------------------+

5 rows in set (0.00 sec)

 

mysql> 

Waiting for table metadata lock

会话连接(connection id=17)执行下面SQL语句,模拟一个慢查询SQL

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|              17 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> select name, sleep(100) from test;

会话连接(connection id=6)执行下面SQL语句, 修改表结构操作

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|               6 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> alter table test add tname varchar(10); // rename table test to kkk 同样会引起Waiting for table metadata lock

会话连接(connection id=8)执行下面SQL语句,查询表test

mysql> select connection_id();

+-----------------+

| connection_id() |

+-----------------+

|               8 |

+-----------------+

1 row in set (0.00 sec)

 

mysql> select * from test;

查看线程的状态,你会发现被阻塞的会话处于 Waiting for table metadata lock状态。

mysql> show processlist;

+----+------+-----------+------+---------+------+---------------------------------+----------------------------------------+

| Id | User | Host      | db   | Command | Time | State                           | Info                                   |

+----+------+-----------+------+---------+------+---------------------------------+----------------------------------------+

|  6 | root | localhost | MyDB | Query   |   19 | Waiting for table metadata lock | alter table test add tname varchar(10) |

|  8 | root | localhost | MyDB | Query   |    6 | Waiting for table metadata lock | select * from test                     |

| 15 | root | localhost | NULL | Sleep   |    8 |                                 | NULL                                   |

| 16 | root | localhost | NULL | Query   |    0 | init                            | show processlist                       |

| 17 | root | localhost | MyDB | Query   |   55 | User sleep                      | select name, sleep(100) from test      |

+----+------+-----------+------+---------+------+---------------------------------+----------------------------------------+

5 rows in set (0.00 sec)

 

mysql> 

 

 

参考资料:

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/

MySQL进程处于Waiting for table flush的分析的更多相关文章

  1. MySQL线程处于Waiting for table flush的分析

      最近遇到一个案例,很多查询被阻塞没有返回结果,使用show processlist查看,发现不少MySQL线程处于Waiting for table flush状态,查询语句一直被阻塞,只能通过K ...

  2. mysql Waiting for table flush

    应用突然被hang住了,tomcat日志报错,所有涉及到数据库的操作都报错,卡死. show processlist 查看到大量的:Waiting for table flush 应该是 进行了 dd ...

  3. Waiting for table flush 阻塞查询的问题

    1.此状态表示大量thread正在等待慢查询语句执行完成. 原因: The thread got a notification that the underlying structure for a ...

  4. mysql错误: waiting for table metadata lock

    今天突然发现truncate一个表都慢到不行,于是 SHOW PROCESSLIST 发现错误:waiting for table metadata lock解决方法:查看information_sc ...

  5. MySQL - 问题集 - "Waiting for table metadata lock"(待完善)

    待完善.show processlist; 可参考1:http://blog.csdn.net/huochuangchuang/article/details/49423893 可参考2:http:/ ...

  6. 记一次MySQL出现Waiting for table metadata lock的原因、排查过程与解决方法

    任务背景:将sql文件通过shell直接导入到mysql中执行(还原) bug表现:导入后java项目卡死 过程: 1.网上乱搜一通,无意间看到一篇文章,这篇文章说明了如何开启mysql的genera ...

  7. 转 mysql 备份导致 waiting for global read lock

    ######转 https://blog.csdn.net/weixin_34038652/article/details/92129498 近业务高峰期间经常会有开发跳起来说应用连接数据库超时了! ...

  8. 修改字段字符集 mysql 修改 锁表 show processlist; 查看进程 Waiting for table metadata lock

    ALTER TABLE `question` MODIFY COLUMN `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unico ...

  9. 【MySQL经典案例分析】 Waiting for table metadata lock

    本文由云+社区发表 一. 问题是这样来的 ​ 2018年某个周末,接到连续数据库的告警,告警信息如下: 二. 苦逼的探索过程 1.总体的思路 看到too many connection的报错信息,基本 ...

随机推荐

  1. Ionic开发笔记

    Ionic 开发笔记 记录开发中遇到的一些问题 ion-side-menu,使所有顶部导航标题居中 <!-- 添加 align-title="center" 使顶部导航标题居 ...

  2. Java学习笔记之集合

    集合(Collection)(掌握) (1)集合的由来? 我们学习的是Java -- 面向对象 -- 操作很多对象 -- 存储 -- 容器(数组和StringBuffer) -- 数组而数组的长度固定 ...

  3. 同网段电脑互ping

    两台同网段的主机(host)之间的网络通信是不经过网关的. 今天试了一下,用一根网线连接两台电脑,然后 在一台电脑上设置: ip地址:192.168.0.1 子网掩码:255.255.255.0 在另 ...

  4. Java jvm级别native关键词、JNI详解

    1.native关键词的引入 再完美的编程语言也有自己的不足之处,当然Java也不例外,Java的不足之处除了体现在运行速度(这点往往被一些其他编程语言使用者所诟病)上要比传统的C++慢许多之外,Ja ...

  5. Struts2请求参数合法性校验机制

    在Action中通过代码执行数据校验 请求参数的输入校验途径一般分两种:客户端校验 :通过JavaScript 完成 (jquery validation插件),目的:过滤正常用户的误操作. 服务器校 ...

  6. Unity3D-Shader-人物残影效果

    [旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...

  7. java在控制台输出空心正方形,菱形,空心菱形

     使用for和if打印一个空心正方形 /*思路:要想打印一个5x5的空心正方形,首先它的第一横行和最后一行都是填满的,需要全部遍历出来,第二三四行和只有左右两条边是出来的,中间部分为空的.因此在打印第 ...

  8. 安装wdcp linux一键安装包云系统客户端教程

    首先把自己阿里云的磁盘格式化然后重启 自己下载一个PuTTY 打开后输入自己的Ip地址端口号默认是22 会跳出一个yes 跟no界面,点击yes 会进入一个类似cmd界面 直接输入root,然后会提示 ...

  9. PHP+js实现图片上传,编辑

    文件上传,点击按钮并选择文件后,文件会临时存到一个位置,会有一个临时名字: 然后在php文件中处理,给文件起名并将文件从临时为止搬到服务器,把需要的文件信息返回给前端页面: 最后表单提交时,把文件信息 ...

  10. synchronized Lock用法

    在介绍Lock与synchronized时,先介绍下Lock: public interface Lock { void lock(); void lockInterruptibly() throws ...