1. 程式人生 > >MySQL部分從庫上面因為大量的臨時表tmp_table造成慢查詢

MySQL部分從庫上面因為大量的臨時表tmp_table造成慢查詢

status 方式 png star stat 什麽 bubuko -- img

背景描述

# Time: 2019-01-24T00:08:14.705724+08:00
# User@Host: **[**] @  [**]  Id: **
# Schema: sentrymeta  Last_errno: 0  Killed: 0
# Query_time: 0.315758  Lock_time: 0.001693  Rows_sent: 9664  Rows_examined: 36413  Rows_affected: 0
# Bytes_sent: 1616970  Tmp_tables: 1  Tmp_disk_tables: 1  Tmp_table_sizes: 16384
# QC_Hit: No  Full_scan: No  Full_join: No  Tmp_table: Yes  Tmp_table_on_disk: Yes
# Filesort: No  Filesort_on_disk: No  Merge_passes: 
0 # InnoDB_IO_r_ops: 0 InnoDB_IO_r_bytes: 0 InnoDB_IO_r_wait: 0.000000 # InnoDB_rec_lock_wait: 0.000000 InnoDB_queue_wait: 0.000000 # InnoDB_pages_distinct: 1085
             total       used       free     shared    buffers     cached
Mem:           125         38         87          0          0         19
-/+ buffers/cache:         18
107 Swap: 31 0 31
root@(none)04:33:02>select version();
+---------------+
| version()     |
+---------------+
| 5.7.19-17-log |
+---------------+
1 row in set (0.00 sec)

root@(none)04:33:07>show variables like %table_size%;
+---------------------+-----------+
| Variable_name       |
Value | +---------------------+-----------+ | max_heap_table_size | 134217728 | | tmp_table_size | 16777216 | +---------------------+-----------+ 2 rows in set (0.00 sec)

問題分析

Q1:為什麽會產生臨時表?

這個不多說,SQL寫的惹不起,反正就是半個小時看不懂的那種,就是一眼就知道一定會產生臨時表的??~~~

Q2:登錄到機器上去查看內存使用偏小?

因為這個物理機的內存是125G,但是mysql的總數據量不超過1G,所有實際並不需要多少內存就可以將所有數據都加載都內存中。

Q3:既然內存夠用,為啥還要在磁盤上產生臨時表?

後面可以看見數據庫配置的臨時表空間是16M,從慢查詢日誌上來看每一個臨時表的大小是16K,在QPS達到一定量了之後,臨時表空間就達到了上限,就會產生臨時磁盤表,看圖下面的產生的【臨時磁盤表/臨時表】的比例也是符合預期,現在大概就每3條SQL其中有一條會產生臨時表。解決辦法就是把tmp_table_size這個參數調大,按照當前的計算,調大一半8M可以解決問題。但是,我現在的機器配置很豪,就開心的調大10倍啦~~~~

技術分享圖片

Q4:磁盤上產生臨時表真的是SQL慢的根本原因嗎?

通常我們會認為產生了臨時表,就更不用說臨時磁盤表,大部分就能確定慢查詢的原因了。但是這次我還是懷疑了一下,實在是機器性能太好,想著16K的臨時表真的有這麽大的影響嗎,而且我的磁盤性能【SSD、PCIE】感覺也很棒,O(∩_∩)O哈哈~。所以我統計了一下各個階段的執行時間,發現 converting HEAP to ondisk 從內存中拷貝數據到磁盤消耗的時間並不多,16K對於這種高配的機器還是小case,真正的時間消耗在sending data上,為啥會這樣呢?看上面的慢查詢日誌發現 Bytes_sent: 1616970 這個是1.54M,消耗時間比較多的是從引擎層發送數據給server層,因為這個SQL最後訪問的數據比較多。做個簡單測試,右邊是原來的SQL執行時間,左邊是我limit 5的統計結果,可以很直觀的看到sending data時間上的差異,時間上查了0.011001/0.000131 ~ 84倍。但是這個和數據行數並不是線性增長關系的,原因嘛就是磁盤的訪問方式。

show profile for query 8;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000082 |
| checking permissions | 0.000003 |
| checking permissions | 0.000001 |
| checking permissions | 0.000003 |
| Opening tables       | 0.000015 |
| init                 | 0.000024 |
| System lock          | 0.000010 |
| optimizing           | 0.000010 |
| statistics           | 0.000098 |
| preparing            | 0.000014 |
| Creating tmp table   | 0.000033 |
| executing            | 0.000002 |
| Sending data         | 0.000131 |
| end                  | 0.000003 |
| query end            | 0.000005 |
| removing tmp table   | 0.000049 |
| query end            | 0.000002 |
| closing tables       | 0.000015 |
| freeing items        | 0.000030 |
| cleaning up          | 0.000017 |
+----------------------+----------+
20 rows in set, 1 warning (0.00 sec)

show profile for query 1;
+---------------------------+----------+
| Status                    | Duration |
+---------------------------+----------+
| starting                  | 0.000165 |
| checking permissions      | 0.000005 |
| checking permissions      | 0.000002 |
| checking permissions      | 0.000006 |
| Opening tables            | 0.000027 |
| init                      | 0.000057 |
| System lock               | 0.000015 |
| optimizing                | 0.000025 |
| statistics                | 0.000235 |
| preparing                 | 0.000031 |
| Creating tmp table        | 0.000066 |
| executing                 | 0.000003 |
| Sending data              | 0.011001 |
| converting HEAP to ondisk | 0.005307 |
| Sending data              | 0.059461 |
| end                       | 0.000004 |
| query end                 | 0.000011 |
| removing tmp table        | 0.000137 |
| query end                 | 0.000004 |
| closing tables            | 0.000026 |
| freeing items             | 0.000026 |
| cleaning up               | 0.000022 |
+---------------------------+----------+
22 rows in set, 1 warning (0.00 sec)



MySQL部分從庫上面因為大量的臨時表tmp_table造成慢查詢