上面一篇文章已經將慢查詢語句記錄到日誌中,接着我們就要對單條SQL查詢進行性能分析,瞭解它慢在何處,才能對症下藥進行性能優化。
show profile
show profile
命令是MySQL5.1之後引入的,由開源社區的Jeremy Cole貢獻。
1. 開啓profiling
profiling
系統變量是用來支持訪問剖析信息的,profiling
默認是關閉的,我們可以用set profiling=1
命令開啓profile。
mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
| 0 |
+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
| 1 |
+-------------+
1 row in set, 1 warning (0.00 sec)
查看系統變量除了使用
show variables
命令外,還可以使用select @@
語句,其中@@
用來訪問系統變量,一個@
用來訪問用戶自定義變量。設置變量值可以使用set
命令,命令語法如下:SET variable_assignment [, variable_assignment] …
variable_assignment:
user_var_name = expr
| param_name = expr
| local_var_name = expr
| [GLOBAL | SESSION]
system_var_name = expr
| [@@global. | @@session. | @@]
system_var_name = exprset命令更多詳細內容可以參考MySQL官方手冊
2. show profiles
show profiles
命令用來顯示當前會話最近執行語句的耗時情況。
mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show profiles;
Empty set, 1 warning (0.00 sec)
mysql> show databases;
+----------------------+
| Database |
+----------------------+
| information_schema |
| db_cnilink |
| db_internation_trade |
| db_oa |
| db_privilege |
| db_spring_jpa |
| db_tao_market |
| db_zheng |
| mysql |
| performance_schema |
| sys |
| test |
+----------------------+
12 rows in set (0.01 sec)
mysql> use test;
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| dept |
| emp |
+----------------+
7 rows in set (0.00 sec)
mysql> select * from emp;
+-------+-------+------------+------+---------------------+------+------+--------+
| empno | ename | job | mgr | hireDate | sal | comm | deptno |
+-------+-------+------------+------+---------------------+------+------+--------+
| 1 | 張三 | 系統架構師 | NULL | 2015-01-07 18:30:25 | 20 | 20 | 1 |
| 2 | 李四 | 掃地員工 | NULL | 2015-01-07 18:30:25 | 20 | 20 | 1 |
| 3 | SMITH | 軟件設計師 | 1 | 2017-11-15 16:12:00 | 10 | 10 | 2 |
| 4 | SMITH | 軟件設計師 | 1 | 2017-11-15 16:24:25 | 10 | 10 | 2 |
+-------+-------+------------+------+---------------------+------+------+--------+
4 rows in set (0.01 sec)
mysql> show profiles;
+----------+------------+-------------------+
| Query_ID | Duration | Query |
+----------+------------+-------------------+
| 1 | 0.00629075 | show databases |
| 2 | 0.00312050 | SELECT DATABASE() |
| 3 | 0.00216050 | show tables |
| 4 | 0.01549250 | select * from emp |
+----------+------------+-------------------+
4 rows in set, 1 warning (0.00 sec)
可以看到show profiles展示了最近執行的四條查詢語句。show profiles
默認保存15條性能剖析信息,可以通過profiling_history_size
系統變量來修改這個值,注意這個變量最大值爲100。
3. show profile
我們要看到某一條查詢的詳細性能剖析信息,需要用到show profile
命令。
mysql> show profiles;
+----------+------------+-------------------+
| Query_ID | Duration | Query |
+----------+------------+-------------------+
| 1 | 0.00629075 | show databases |
| 2 | 0.00312050 | SELECT DATABASE() |
| 3 | 0.00216050 | show tables |
| 4 | 0.01549250 | select * from emp |
+----------+------------+-------------------+
4 rows in set, 1 warning (0.00 sec)
# show profile命令默認顯示最近一條查詢的剖析信息
mysql> show profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.002576 |
| checking permissions | 0.000011 |
| Opening tables | 0.008276 |
| init | 0.000052 |
| System lock | 0.000026 |
| optimizing | 0.000008 |
| statistics | 0.000026 |
| preparing | 0.000021 |
| executing | 0.000002 |
| Sending data | 0.000816 |
| end | 0.000007 |
| query end | 0.000007 |
| closing tables | 0.000009 |
| freeing items | 0.000079 |
| logging slow query | 0.000007 |
| Opening tables | 0.000163 |
| System lock | 0.003389 |
| cleaning up | 0.000019 |
+----------------------+----------+
18 rows in set, 1 warning (0.00 sec)
# 要獲取更早的查詢剖析信息要用for query字句
# for query字句後面跟QUERY_ID
mysql> show profile for query 3;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.001741 |
| checking permissions | 0.000010 |
| checking permissions | 0.000002 |
| Opening tables | 0.000040 |
| init | 0.000009 |
| System lock | 0.000005 |
| optimizing | 0.000006 |
| statistics | 0.000012 |
| preparing | 0.000010 |
| executing | 0.000005 |
| checking permissions | 0.000220 |
| Sending data | 0.000016 |
| end | 0.000003 |
| query end | 0.000004 |
| closing tables | 0.000002 |
| removing tmp table | 0.000004 |
| closing tables | 0.000003 |
| freeing items | 0.000055 |
| cleaning up | 0.000016 |
+----------------------+----------+
19 rows in set, 1 warning (0.00 sec)
從show profile
可以清楚地看到查詢語句每個階段的耗時情況。
關於show profile命令的更多語法查看官方手冊:https://dev.mysql.com/doc/refman/5.7/en/show-profile.html
4. 直接查詢INFORMATION_SCHEMA.PROFILING表
show profile
命令列出來的信息的確很詳細,但是我們無法快速的確定哪個步驟花費的時間最多,因爲輸出的順序是按照語句執行的順序排列的。但是我們實際更關心的是哪些部分開銷較大,但是很不幸show profile命令暫時不支持order by這樣的排序功能。實際上profile的性能剖析信息都存在information_schema數據庫的profiling表中。
mysql> set @query_id=4;
Query OK, 0 rows affected (0.00 sec)
mysql> select state,sum(duration) as Total_R,
-> round(
-> 100 * sum(duration) /
-> (select sum(duration) from information_schema.profiling
-> where query_id=@query_id
-> ),2) as Pct_R,
-> count(*) as Calls,
-> sum(duration) / count(*) as 'R/Call'
-> from information_schema.profiling
-> where query_id=@query_id
-> group by state
-> order by Total_R desc;
+----------------------+----------+-------+-------+--------------+
| state | Total_R | Pct_R | Calls | R/Call |
+----------------------+----------+-------+-------+--------------+
| Opening tables | 0.008439 | 54.47 | 2 | 0.0042195000 |
| System lock | 0.003415 | 22.04 | 2 | 0.0017075000 |
| starting | 0.002576 | 16.63 | 1 | 0.0025760000 |
| Sending data | 0.000816 | 5.27 | 1 | 0.0008160000 |
| freeing items | 0.000079 | 0.51 | 1 | 0.0000790000 |
| init | 0.000052 | 0.34 | 1 | 0.0000520000 |
| statistics | 0.000026 | 0.17 | 1 | 0.0000260000 |
| preparing | 0.000021 | 0.14 | 1 | 0.0000210000 |
| cleaning up | 0.000019 | 0.12 | 1 | 0.0000190000 |
| checking permissions | 0.000011 | 0.07 | 1 | 0.0000110000 |
| closing tables | 0.000009 | 0.06 | 1 | 0.0000090000 |
| optimizing | 0.000008 | 0.05 | 1 | 0.0000080000 |
| logging slow query | 0.000007 | 0.05 | 1 | 0.0000070000 |
| query end | 0.000007 | 0.05 | 1 | 0.0000070000 |
| end | 0.000007 | 0.05 | 1 | 0.0000070000 |
| executing | 0.000002 | 0.01 | 1 | 0.0000020000 |
+----------------------+----------+-------+-------+--------------+
16 rows in set, 17 warnings (0.01 sec)
上面的查詢語句參考自《高性能MySQL》第三版3.3節。
通過這個查詢可以清楚地看到最耗時的部分。
通過看官方手冊對explain的解釋發現,describe
(可簡寫成desc
)和explain
可以混着用(MySQL解析器將它們視爲同義詞),只是大多數情況下更喜歡用desc
來查看錶結構(事實上是對show columns
命令的簡化,主要爲了兼容Oracle數據庫),使用explain
來查看執行計劃(即解析MySQL是如何執行查詢語句的)。
使用explain獲取執行計劃
我們可以使用explain
來獲取select
,delete
,insert
,replace
,update
這幾個語句經過MySQL優化器優化後的執行計劃。
mysql> explain select * from test.emp \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: emp
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
mysql裏面默認以
;
作爲一條完整語句的終結符,但是可以通過delimiter
(縮寫\d
)命令進行修改,可以使用go
(縮寫\g
)命令將SQL語句發送到服務器,使用ego
(縮寫\G
)命令可以讓返回的查詢結果垂直顯示。
下表是上面explain命令返回結果各列的意義(其中json name是以explain format=json
執行計劃分析返回的結果):
column | json name | meaning |
---|---|---|
id |
select_id |
該SELECT 查詢的標識符 |
select_type |
沒有 | 該SELECT 查詢的類型,常見的取值有SIMPLE ,PRIMARY ,UNION ,SUBQUERY ,DERIVED (from子句中的子查詢)等 |
table |
table_name |
查詢用到了哪些表 |
partitions |
partitions |
匹配的分區(分區表) |
type |
access_type |
連接join類型(從好到壞):system -> const -> eq_ref -> ref -> fulltext -> ref_or_null -> index_merge -> unique_subquery -> index_subquery -> range -> index -> ALL 。詳細請參考官方手冊。 |
possible_keys |
possible_keys |
可能選用的索引(可能有多個),可以在查詢中用 FORCE INDEX ,USE INDEX 或IGNORE INDEX 來強制使用(或不適用)某個特定的索引。 |
key |
key |
實際選擇選用的索引,大多數情況下和possible_keys 值相同。如果爲NULL,說明語句沒有用到索引。 |
key_len |
key_length |
使用索引的長度,這個值可以確定MySQL實際使用了索引的哪些部分(複合索引經常出現只用到索引的前幾列的情況)。 |
ref |
ref |
與索引進行比較的列(哪些列用到了索引) |
rows |
rows |
要掃描的行的估計值(對於InnoDB,這個數字是估計值) |
filtered |
filtered |
表條件過濾的行的百分比(rows * filtered% 與前一張表進行join連接的行數) |
Extra |
沒有 | 附加信息,常見的附加信息如:Using index ,Using filesort ,Using join buffer ,Using temporary ,Using where 。更多附加信息參考官方手冊 |
關於explain這部分內容就不贅述了,官方手冊給了詳細的解釋和例子。
參考:
《高性能MySQL》
MySQL官方手冊:https://dev.mysql.com/doc/refman/5.7/en/
http://blog.csdn.net/littleboyandgirl/article/details/68486642