这篇文章主要介绍“MySQL中sending data状态包含了什么”,在日常操作中,相信很多人在MySQL中sending data状态包含了什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL中sending data状态包含了什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、问题由来

原问题如下:

数据库发送数据给客户端这个时间算是sql的执行时间嘛?

要解决问题我们需要知道MySQL何时将数据传输给了客户端,既然是要传输实际的数据给客户端那么肯定是select语句了,同时我们要明白一个正常select运行到底要经历哪些阶段。

二、一个简单SELECT语句经历的阶段

2392T@10:|||||THD::enter_stage:'checkingpermissions'/root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authorization.cc:8432404T@10:||||||THD::enter_stage:'Openingtables'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_base.cc:57192512T@10:|||||THD::enter_stage:'init'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_select.cc:1212681T@10:|||||||THD::enter_stage:'Systemlock'/root/mysql5.7.14/percona-server-5.7.14-7/sql/lock.cc:3212772T@10:|||||||THD::enter_stage:'optimizing'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_optimizer.cc:1512865T@10:|||||||THD::enter_stage:'statistics'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_optimizer.cc:3863329T@10:|||||||THD::enter_stage:'preparing'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_optimizer.cc:4943466T@10:||||||THD::enter_stage:'executing'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_executor.cc:1193474T@10:||||||THD::enter_stage:'Sendingdata'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_executor.cc:1953668T@10:|||||THD::enter_stage:'end'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_select.cc:1993685T@10:||||THD::enter_stage:'queryend'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_parse.cc:51743754T@10:||||THD::enter_stage:'closingtables'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_parse.cc:52523882T@10:|||THD::enter_stage:'freeingitems'/root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_parse.cc:5855

实际上整个阶段都算到了语句的实际消耗时间之中的,但是慢查询记录的是:

实际执行时间 = (freeing items 末端的时间) 实际消耗时间 - (System lock末端的时间 )比如MDL LOCK等待时间 - (Innodb层锁定的时间)行锁等待消耗时间

关于慢查询的详细情况可以参考我的一篇文章,这里不再重述。

https://www.jianshu.com/p/1ffadf29d6c0MySQL慢查询记录原理和内容解析三、什么是Sending data状态

实际上这个状态是select语句才会有的,如果是DML则不同但是都有等同的阶段如下:

select:Sending data

insert语句:Update

delete/update:Updating

这个阶段非常的巨大,它至少包含了:

Innodb 层数据的定位返回给MySQL 层

Innodb 层数据的查询返回给MySQL 层

Innodb 层数据的修改(如果是MDL)

Innodb 层加锁以及等待

等待进入Innodb层(innodb_thread_concurrency参数)

MySQL 层发送数据给客户端

可以看到基本所有和Innodb层打交道的过程都包裹在这个状态下面,当然我只是列举了我想到的一些,其实可能还有很多很多,这里我也把MySQL 层发送数据给客户端包含在 Sending data的答案给出了,下面我们进行分析。

四、如何证明Sending data状态包含了网络数据传输的时间

之前你可以参考一下我的文章

https://www.jianshu.com/p/25fed8f1f05eMySQL:Innodb Handler_read_*变量解释

我们建立一个简单的表如下,并且填充数据如下:

CreateTable:CREATETABLE`ty`(`id`int(11)NOTNULLAUTO_INCREMENT,`a`int(11)DEFAULTNULL,`b`int(11)DEFAULTNULL,PRIMARYKEY(`id`),KEY`idxa`(`a`))ENGINE=InnoDBAUTO_INCREMENT=12DEFAULTCHARSET=utf8mb4mysql>select*fromty;+----+------+------+|id|a|b|+----+------+------+|8|2|3||9|5|4||10|6|7||11|6|8|+----+------+------+4rowsinset(4.14sec)

我们执行如下语句:

mysql>descselect*fromtywherea=6andb=8;+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+|1|SIMPLE|ty|NULL|ref|idxa|idxa|5|const|2|33.33|Usingwhere|+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+mysql>select*fromtywherea=6andb=8;+----+------+------+|id|a|b|+----+------+------+|11|6|8|+----+------+------+1rowinset(7.22sec)

注意:这里的语句执行时间很长是因为我打了GDB断点所以看起来很久而已
我做了语句的trace,这个语句大概需要如下步骤:

首先Innodb定位到索引idxa数据6所在位置这是初次定位调用函数ha_innobase::index_read,返回数据| 10 | 6 | 7 |给MySQL层,但是MySQL层过滤掉不符合条件 a =6 and b=8 不需要返回给客户端。

1547T@12:||||||||>handler::ha_index_read_map1548T@12:|||||||||>index_read(这里进行初次访问索引定位)1552T@12:||||||||||>row_search_mvcc1553T@12:|||||||||||>btr_cur_search_to_nth_level1554T@12:|||||||||||<btr_cur_search_to_nth_level2009...1593T@12:||||||||||<row_search_mvcc60701594T@12:|||||||||<index_read91791595T@12:||||||||<handler::ha_index_read_map31901596T@12:||||||||>evaluate_join_record(这里进入MySQL层where条件判断流程,不满足不发送)...1600T@12:||||||||<evaluate_join_record1701

定位完成后再次访问索引idxa的下一条数据,Innodb直接读取就好了调用函数ha_innobase::index_next_same,返回数据| 11 | 6 | 8 |给Mysql层,因为满足条件 a =6 and b=8所以返回给客户端

1601T@12:||||||||>handler::ha_index_next_same(这里就是顺序访问索引的下一行数据了)1602T@12:|||||||||>general_fetch1603T@12:||||||||||>row_search_mvcc....1607T@12:||||||||||<row_search_mvcc60701608T@12:|||||||||<general_fetch94871609T@12:||||||||<handler::ha_index_next_same34141610T@12:||||||||>evaluate_join_record(这里进入MySQL层where条件判断流程,满足条件需要发送)1613T@12:|||||||||>end_send1614T@12:||||||||||>Query_result_send::send_data(这里就是发送数据给客户端了,也就是通过网络发送数据给客户端了)1615T@12:|||||||||||>send_result_set_row1616T@12:|||||||||||<send_result_set_row49671620T@12:||||||||||<Query_result_send::send_data29151621T@12:||||||||||>Protocol_classic::end_row1622T@12:||||||||||<Protocol_classic::end_row11981625T@12:|||||||||<end_send29911626T@12:||||||||<evaluate_join_record1701

因为是非唯一索引因此需要再次访问下一条数据来判断已经读取了所有a=6的数据,因此Innodb需要在读取索引idxa的下一条数据调用函数ha_innobase::index_next_same。

1627T@12:||||||||>handler::ha_index_next_same(这里就是顺序访问索引的下一行数据了)1628T@12:|||||||||>general_fetch1629T@12:||||||||||>row_search_mvcc...1639T@12:||||||||||<row_search_mvcc60701640T@12:|||||||||<general_fetch94871641T@12:||||||||<handler::ha_index_next_same3414

所以总结整个流程一共经历了一次索引定位,两次索引顺序读取,一共读取了三条数据,但是返回给MySQL层的只有前面两条数据,通过MySQL层的过滤只发送给了客户端一条满足条件的数据。

到此,关于“MySQL中sending data状态包含了什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!