SQL 效能分析利器 show profile
在之前的文章中,我們提到過一些慢SQL優化的步驟。其中就包括:
-
使用 explain 關鍵字來檢視執行計劃,是否命中索引。
-
通過計算某列的區分度,來判斷該列是否適合新建索引。
這都是一些比較好的方法。但我們還是不知道,慢SQL,到底慢在哪個環節?在每個環節中耗時是多少?
根據木桶定理,我們應該找到耗時最長,效能最低,也就是最慢的環節,才能分析出慢SQL為什麼這麼慢,以便更加有效的解決這個問題。帶著這個疑問,我們一起來看看今天給大家介紹的這個利器。
開啟效能分析
show profiles 這個命令非常強大,能清晰的展示每條SQL的持續時間。通常結合show profile
-
開啟命令:
set profiling = ON;
或:
set profiling = 1;
-
檢視是否生效:
mysql> show variables like "profiling"; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | profiling | ON | +---------------+-------+ 1 row in set (0.00 sec)
Value的取值範圍有兩個:其中 ON 為開啟狀態,OFF為關閉狀態。
值得注意的是:通過上述命令開啟後僅在當前會話有效。
show profiles
show profiles 其作用為顯示當前會話伺服器最新收到的15條SQL的效能資訊。
其中包括:持續時間,以及Query_ID。我們可以通過Query_ID分析其效能
如下所示:
mysql> show profiles; +----------+------------+---------------------------------+ | Query_ID | Duration | Query | +----------+------------+---------------------------------+ | 1 | 0.00385450 | show variables like "profiling" | | 2 | 0.00170050 | show variables like "profiling" | | 3 | 0.00038025 | select * from t_base_user | +----------+------------+---------------------------------+
其中:
-
Query_ID 表示執行SQL的唯一標識。
-
Duration 表示持續時間,預設單位為秒。
-
Query 就是我們所執行的SQL語句。
注意:
-
show profiles 語句 預設顯示的是服務端接收到的最新的15條語句。
我們可以通過以下語句進行修改預設值:set profiling_history_size =20;
profiling_history_size最大取值取值範圍為[0,100]。
-
當超過100時,則會設定自動設定為最大值100。
-
當小於0時,則會自動設定最小值為0。
-
當其等於0時,其效果等同於
set profiling=0
,關閉效能分析模式。
現在通過 show profiles 命令檢視到了SQL的執行時間,但這是一個總時間,每一步的耗時怎麼看呢?別急,我們再來看看show profile 命令的用法。
show profile
還記得show profiles命令中的 Query_ID欄位嗎?我們現在就通過Query_ID來檢視下持續時間的構成。
例如:我們檢視Query_ID 等於 3 的詳細持續時間構成。
如下所示:
mysql> show profile for query 3;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000081 |
| checking permissions | 0.000012 |
| Opening tables | 0.000028 |
| init | 0.000029 |
| System lock | 0.000017 |
| optimizing | 0.000006 |
| statistics | 0.000025 |
| preparing | 0.000018 |
| executing | 0.000004 |
| Sending data | 0.000087 |
| end | 0.000007 |
| query end | 0.000012 |
| closing tables | 0.000013 |
| freeing items | 0.000023 |
| cleaning up | 0.000021 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)
通過上述結果,我們可以非常清楚的檢視每一步的耗時,其中(Druation的單位為秒)。這樣,當我們遇到一條慢SQL時,就能很清楚的知道,為什麼慢,慢在哪一步了。
備註: 上述結果集中的Status就不再詳細解析了,這裡其實展示的是SQL的執行過程,經歷的步驟,通過字面就能很快知道其意思。
上面我們使用的是預設展示結果。其實,我們也指定展示結果,如:CPU,IO,執行緒上下文切換等等。
可選引數如下:
-
all: 展示所有資訊。
-
block io: 展示io的輸入輸出資訊。
-
context switches: 展示執行緒的上線文切換資訊。
-
cpu :顯示SQL 佔用的CPU資訊。
-
ipc: 顯示統計訊息的傳送與接收計數資訊。
-
page faults:顯示主要與次要的頁面錯誤。
-
memory:本意是顯示記憶體資訊,但目前還未實現。
-
swaps: 顯示交換次數。
-
sources:顯示原始碼中的函式名稱,以及函式發生的檔案的名稱和行。
上面引數可以組合使用,其中用 , 號分割。如下所示:
mysql> show profile block io,cpu for query 3;
+----------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000081 | 0.000036 | 0.000044 | 0 | 0 |
| checking permissions | 0.000012 | 0.000005 | 0.000006 | 0 | 0 |
| Opening tables | 0.000028 | 0.000013 | 0.000015 | 0 | 0 |
| init | 0.000029 | 0.000013 | 0.000016 | 0 | 0 |
| System lock | 0.000017 | 0.000008 | 0.000009 | 0 | 0 |
| optimizing | 0.000006 | 0.000002 | 0.000003 | 0 | 0 |
| statistics | 0.000025 | 0.000011 | 0.000013 | 0 | 0 |
| preparing | 0.000018 | 0.000008 | 0.000010 | 0 | 0 |
| executing | 0.000004 | 0.000002 | 0.000002 | 0 | 0 |
| Sending data | 0.000087 | 0.000040 | 0.000048 | 0 | 0 |
| end | 0.000007 | 0.000003 | 0.000003 | 0 | 0 |
| query end | 0.000012 | 0.000006 | 0.000007 | 0 | 0 |
| closing tables | 0.000013 | 0.000005 | 0.000006 | 0 | 0 |
| freeing items | 0.000023 | 0.000011 | 0.000013 | 0 | 0 |
| cleaning up | 0.000021 | 0.000009 | 0.000011 | 0 | 0 |
+----------------------+----------+----------+------------+--------------+---------------+
15 rows in set, 1 warning (0.00 sec)
當結果顯示的比較多時,你也可以通過 limit 選項,來顯示指定的行數。如下所示:
mysql> show profile block io,cpu for query 3 limit 2;
+----------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000081 | 0.000036 | 0.000044 | 0 | 0 |
| checking permissions | 0.000012 | 0.000005 | 0.000006 | 0 | 0 |
+----------------------+----------+----------+------------+--------------+---------------+
2 rows in set, 1 warning (0.00 sec)
現在我們就可以很清楚的知道,慢SQL到底慢在哪?可以進行鍼對性的優化。我們對優化後的SQL語句也能檢視其持續時間,是否符合我們的指標。
PS: 最近在面試過程中,問及SQL優化時,有很多的同學對執行計劃,區分度的概念都不是很清楚。甚至覺得執行計劃中有執行時間,這就很離譜了,對不對。我希望我的讀者朋友們不要被這種低階錯誤