资讯

展开

MySQL8.0之Sending data和Sending to client的区别

作者:快盘下载 人气:

//

mysql8.0之Sending data和Sending to client的区别

//

日常的MySQL运维工作中,我们经常会使用到show processlist这样的语法,来查看当前数据库上面的连接情况。show processlist语法的返回过程中,经常会看到sending data和sending to client的状态。今天来看看这两个状态的区别。

首先查阅官方文档中的描述:(给出官网地址)

https://dev.mysql.com/doc/refman/8.0/en/general-thread-states.html

在MySQL中,将show processlist的结果状态分为8个大的类,分别是:

Thread Command ValuesGeneral Thread StatesReplication Source Thread StatesReplication I/O Thread StatesReplication SQL Thread StatesReplication Connection Thread StatesNDB Cluster Thread StatesEvent Scheduler Thread States

首先我们需要知道,我们所讨论的这两种状态,是数据通用线程状态里面的。现在我们看看这两个状态的解释:

sending data(或者叫executing)状态:

从描述中不难看出来,Sending data这个状态,在后续的8.0.17版本之后,会自动并入Executing之中,它表示当前SQL查询已经进入了执行阶段,接下来要发送结果给客户端、然后继续执行语句。简单理解,就是Sending data状态,代表这个SQL处于执行阶段的任意时刻。即使在有锁等待的情况下,依旧会显示为Sending data。

8.0.19版本中的实验如下:

在会话1中执行:

[yeyz] 23:40:04> begin;
Query OK, 0 rows affected (0.00 sec)

[yeyz] 23:40:07> select * from a for update;
+------+------+
| f1   | f2   |
+------+------+
|    1 |    1 |
|    2 |    2 |
|    3 |    3 |
|    4 |    4 |
|    5 |    5 |
|    6 |    6 |
+------+------+
6 rows in set (0.00 sec)

会话2中执行下面操作,并使用show processlist:

[yeyz] 23:23:38> begin;
Query OK, 0 rows affected (0.01 sec)

[yeyz] 23:35:18> select * from a lock in share mode;
+------+------+
| f1   | f2   |
+------+------+
|    1 |    1 |
|    2 |    2 |
|    3 |    3 |
|    4 |    4 |
|    5 |    5 |
|    6 |    6 |
+------+------+
6 rows in set (0.03 sec)

[yeyz] 23:35:31> show processlist;
+----------+----------------+--------------------+------+------------------+----------+---------------------------------------------------------------+----------------------------+
| Id       | User           | Host               | db   | Command          | Time     | State                                                         | Info                       |
+----------+----------------+--------------------+------+------------------+----------+---------------------------------------------------------------+----------------------------+
| 18050523 | mysqlha_common | xxx:51542          | yeyz | Query            |        0 | starting                                                      | show processlist           |
| 18050534 | mysqlha_common | xxx:56822          | yeyz | Query            |        6 | executing                                                     | select * from a for update |
+----------+----------------+--------------------+------+------------------+----------+---------------------------------------------------------------+----------------------------+
2 rows in set (0.01 sec)

可以看到,这个命令处于executing状态(如果是低版本的MySQL,会显示Sending data),但是很明显,会话2处于锁等待状态。但是给人的感觉像是在给客户端发送数据一样。

总结:Sending data状态或者Executing状态,代表这个语句正在执行,一旦执行完毕,进入数据发送阶段,就不再保持这个状态。

sending to client状态:

这个状态要说清楚,必须引入MySQL的查询流程,MySQL的数据发送给客户端,是要经过3个过程的:

MySQL8.0之Sending data和Sending to client的区别

1、MySQL把数据写入net_buffer,写满net_buffer之后调用接口发送到本地网络棧;

net buffer的相关变量如下:

[yeyz] 23:47:31> show variables like '%net_bu%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| net_buffer_length | 16384 |
+-------------------+-------+
1 row in set (0.01 sec)

2、本地网络棧也叫socket send buffer,它的默认值保存在Linux操作系统下面的路径中:

[root@ ~]# cat /proc/sys/net/core/wmem_default
212992

客户端会请求本地网络棧的内容,将数据发送到客户端的socket receive buffer中

3、客户端去读取socket receive buffer中的内容,如果客户端接收得慢,会导致MySQL服务端由于结果发不出去,这个事务的执行时间变长

总结:

如果show processlist看到的State的值一直处于“Sending to client”,说明SQL这个语句已经执行完毕,而此时由于请求的数据太多,MySQL不停写入net buffer,而net buffer又不停的将数据写入服务端的网络棧,服务器端的网络栈(socket send buffer)被写满了,又没有被客户端读取并消化,这时读数据的流程就被MySQL暂停了。直到客户端完全读取了服务端网络棧的数据,这个状态才会消失。

一个比较好缓解上面问题的方案是增大net_buffer_length的值,让MySQL将查询到的所有数据都缓存在net buffer里面,由于SQL执行完毕,没有新的数据写入net buffer,net buffer慢慢的发送给socket send buffer,即使客户端读取的速度慢,但是由于没有新数据,这个Sending to Client的状态自然就消失了。

加载全部内容

相关教程
猜你喜欢
用户评论
快盘暂不提供评论功能!