共計 6137 個字符,預計需要花費 16 分鐘才能閱讀完成。
這篇文章主要介紹“MySQL 中 sending data 狀態包含了什么”,在日常操作中,相信很多人在 MySQL 中 sending data 狀態包含了什么問題上存在疑惑,丸趣 TV 小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”MySQL 中 sending data 狀態包含了什么”的疑惑有所幫助!接下來,請跟著丸趣 TV 小編一起來學習吧!
一、問題由來
原問題如下:
數據庫發送數據給客戶端這個時間算是 sql 的執行時間嘛?
要解決問題我們需要知道 MySQL 何時將數據傳輸給了客戶端,既然是要傳輸實際的數據給客戶端那么肯定是 select 語句了,同時我們要明白一個正常 select 運行到底要經歷哪些階段。
二、一個簡單 SELECT 語句經歷的階段
2392 T@10: | | | | | THD::enter_stage: checking permissions /root/mysql5.7.14/percona-server-5.7.14-7/sql/auth/sql_authorization.cc:843
2404 T@10: | | | | | | THD::enter_stage: Opening tables /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_base.cc:5719
2512 T@10: | | | | | THD::enter_stage: init /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_select.cc:121
2681 T@10: | | | | | | | THD::enter_stage: System lock /root/mysql5.7.14/percona-server-5.7.14-7/sql/lock.cc:321
2772 T@10: | | | | | | | THD::enter_stage: optimizing /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_optimizer.cc:151
2865 T@10: | | | | | | | THD::enter_stage: statistics /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_optimizer.cc:386
3329 T@10: | | | | | | | THD::enter_stage: preparing /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_optimizer.cc:494
3466 T@10: | | | | | | THD::enter_stage: executing /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_executor.cc:119
3474 T@10: | | | | | | THD::enter_stage: Sending data /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_executor.cc:195
3668 T@10: | | | | | THD::enter_stage: end /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_select.cc:199
3685 T@10: | | | | THD::enter_stage: query end /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_parse.cc:5174
3754 T@10: | | | | THD::enter_stage: closing tables /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_parse.cc:5252
3882 T@10: | | | THD::enter_stage: freeing items /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/1ffadf29d6c0
MySQL 慢查詢記錄原理和內容解析三、什么是 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/25fed8f1f05e
MySQL:Innodb Handler_read_* 變量解釋
我們建立一個簡單的表如下,并且填充數據如下:
Create Table: CREATE TABLE `ty` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idxa` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4
mysql select * from ty;
+----+------+------+| id | a | b |+----+------+------+| 8 | 2 | 3 || 9 | 5 | 4 || 10 | 6 | 7 || 11 | 6 | 8 |+----+------+------+4 rows in set (4.14 sec)
我們執行如下語句:
mysql desc select * from ty where a =6 and b=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 | Using where |+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------------+
mysql select * from ty where a =6 and b=8;
+----+------+------+| id | a | b |+----+------+------+| 11 | 6 | 8 |+----+------+------+1 row in set (7.22 sec)
注意:這里的語句執行時間很長是因為我打了 GDB 斷點所以看起來很久而已
我做了語句的 trace,這個語句大概需要如下步驟:
首先 Innodb 定位到索引 idxa 數據 6 所在位置這是初次定位調用函數 ha_innobase::index_read,返回數據 | 10 | 6 | 7 | 給 MySQL 層,但是 MySQL 層過濾掉不符合條件 a =6 and b=8 不需要返回給客戶端。
1547 T@12: | | | | | | | | handler::ha_index_read_map 1548 T@12: | | | | | | | | | index_read (這里進行初次訪問索引定位) 1552 T@12: | | | | | | | | | | row_search_mvcc
1553 T@12: | | | | | | | | | | | btr_cur_search_to_nth_level 1554 T@12: | | | | | | | | | | | btr_cur_search_to_nth_level 2009
1593 T@12: | | | | | | | | | | row_search_mvcc 6070
1594 T@12: | | | | | | | | | index_read 9179
1595 T@12: | | | | | | | | handler::ha_index_read_map 3190
1596 T@12: | | | | | | | | evaluate_join_record (這里進入 MySQL 層 where 條件判斷流程,不滿足不發送)... 1600 T@12: | | | | | | | | evaluate_join_record 1701
定位完成后再次訪問索引 idxa 的下一條數據,Innodb 直接讀取就好了調用函數 ha_innobase::index_next_same,返回數據 | 11 | 6 | 8 | 給 Mysql 層,因為滿足條件 a =6 and b=8 所以返回給客戶端。
1601 T@12: | | | | | | | | handler::ha_index_next_same(這里就是順序訪問索引的下一行數據了) 1602 T@12: | | | | | | | | | general_fetch
1603 T@12: | | | | | | | | | | row_search_mvcc
....
1607 T@12: | | | | | | | | | | row_search_mvcc 6070
1608 T@12: | | | | | | | | | general_fetch 9487
1609 T@12: | | | | | | | | handler::ha_index_next_same 3414
1610 T@12: | | | | | | | | evaluate_join_record(這里進入 MySQL 層 where 條件判斷流程,滿足條件需要發送) 1613 T@12: | | | | | | | | | end_send
1614 T@12: | | | | | | | | | | Query_result_send::send_data(這里就是發送數據給客戶端了,也就是通過網絡發送數據給客戶端了) 1615 T@12: | | | | | | | | | | | send_result_set_row 1616 T@12: | | | | | | | | | | | send_result_set_row 4967
1620 T@12: | | | | | | | | | | Query_result_send::send_data 2915
1621 T@12: | | | | | | | | | | Protocol_classic::end_row
1622 T@12: | | | | | | | | | | Protocol_classic::end_row 1198
1625 T@12: | | | | | | | | | end_send 2991
1626 T@12: | | | | | | | | evaluate_join_record 1701
因為是非唯一索引因此需要再次訪問下一條數據來判斷已經讀取了所有 a = 6 的數據,因此 Innodb 需要在讀取索引 idxa 的下一條數據調用函數 ha_innobase::index_next_same。
1627 T@12: | | | | | | | | handler::ha_index_next_same(這里就是順序訪問索引的下一行數據了) 1628 T@12: | | | | | | | | | general_fetch
1629 T@12: | | | | | | | | | | row_search_mvcc
...
1639 T@12: | | | | | | | | | | row_search_mvcc 6070
1640 T@12: | | | | | | | | | general_fetch 9487
1641 T@12: | | | | | | | | handler::ha_index_next_same 3414
所以總結整個流程一共經歷了一次索引定位,兩次索引順序讀取,一共讀取了三條數據,但是返回給 MySQL 層的只有前面兩條數據,通過 MySQL 層的過濾只發送給了客戶端一條滿足條件的數據。
到此,關于“MySQL 中 sending data 狀態包含了什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注丸趣 TV 網站,丸趣 TV 小編會繼續努力為大家帶來更多實用的文章!