最近有個需求,要修改現有存儲結構,涉及查詢條件和查詢效率的考量,看了幾篇索引和HBase相關的文章,回憶了相關知識,結合項目需求,說說本身的理解和總結。html
前2篇介紹了索引的優勢、索引結構的演化過程以及SQL的執行過程,重點分析了SQL的執行順序和數據的定位過程,錯過的朋友能夠先回顧下:mysql
這篇進入正題,介紹如何查看和分析SQL執行狀況、排查SQL的性能問題,經過本篇介紹,你會了解到:算法
部份內容摘錄了幾個博友的文章,最後會給出文章連接,感謝他們的精彩分析。sql
工做中,MySQL會記錄執行時間比較久的SQL語句,找出這些SQL語句是第一步,重要的是查看SQL語句的執行計劃,對於MySQL執行計劃的獲取,能夠經過explain方式來查看,這條命令的輸出結果可以讓咱們瞭解MySQL優化器是如何執行SQL語句的。微信
MySQL優化器是基於開銷來工做的,是在每條SQL語句執行的時候動態地計算出來的,命令用法十分簡單, 在 SELECT 語句前加上 Explain 就能夠了。post
以基本的員工表爲例,表的結構以下:性能
mysql> show create table employee \G;
*************************** 1. row ***************************
Table: mcc_employee
Create Table: CREATE TABLE `employee` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userId` varchar(50) DEFAULT NULL COMMENT '員工編號',
`userName` varchar(50) DEFAULT NULL COMMENT '員工名稱',
`nickName` varchar(50) DEFAULT NULL COMMENT '暱稱',
`gender` varchar(10) DEFAULT NULL COMMENT '性別',
`mobilePhone` varchar(20) DEFAULT NULL COMMENT '手機號',
`miliao` varchar(100) DEFAULT NULL COMMENT '米聊號',
`email` varchar(100) DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
複製代碼
一個簡單的查詢:優化
mysql> explain select * from employee where id =1 \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employee
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: const
rows: 1
Extra: NULL
1 row in set (0.00 sec)
複製代碼
select_type爲simple說明是一個普通的查詢,不包含子查詢和union查詢。spa
id字段:select查詢的標識符. 每一個select都會自動分配一個惟一的標識符,id數值越大的優先執行,id相同的從上往下順序執行。.net
select_type:select查詢的類型,當沒有子查詢或union查詢時爲simple,有子查詢或union查詢時,有幾種狀況,後面會詳細介紹。
table:標識查詢的是哪一個表,顯示這一行的數據是關於哪張表的,有時不是真實的表名字,看到的是derived(n是個數字,爲id字段)
mysql> explain select * from (select * from (select * from employee where id =76) table1 ) table2 ;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL |
| 2 | DERIVED | <derived3> | system | NULL | NULL | NULL | NULL | 1 | NULL |
| 3 | DERIVED | mcc_inform | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
複製代碼
type:數據訪問、讀取操做類型,對性能影響比較大,後面會詳細介紹。
possible_keys:這次查詢中可能選用的索引,查詢涉及到的字段上若存在索引,則該索引將被列出,但不必定被查詢使用。
key:這次查詢中確切使用到的索引,若是沒有選擇索引,鍵是NULL。
key_len:表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度。
ref: 哪一個字段或常數與key一塊兒被使用。
rows: 此查詢一共掃描了多少行,這個是一個估計值。
filtered: 表示此查詢條件所過濾的數據的百分比。
extra: 額外的信息,後面會詳細介紹。
表示查詢的類型,是簡單查詢或複雜查詢,若是是複雜查詢,包含SIMPLE、SIMPLE、UNION、UNION RESULT、SUBQUERY、DEPENDENT、DEPENDENT UNION、DEPENDENT SUBQUERY、DERIVED等,瞭解這些,能夠識別在執行那部分。
簡單select,不使用union或子查詢等:
mysql> explain select * from employee where id =1 ;
+----+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
+----+-------------+------------+-------+---------------+---------+---------+-------+------+-------+
複製代碼
若是是複雜查詢,表示是最外層的select:
mysql> explain select * from (select * from employee where id =1) a ;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL |
| 2 | DERIVED | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
複製代碼
UNION中的第二個或後面的SELECT語句,UNION RESULT爲UNION的結果:
mysql> explain select * from employee where id =1 union all select * from employee where id=2;
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
| 1 | PRIMARY | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
| 2 | UNION | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
複製代碼
子查詢中的第一個SELECT:
mysql> explain select * from employee where id = (select id from employee where id =1);
+----+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | PRIMARY | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
| 2 | SUBQUERY | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | Using index |
+----+-------------+------------+-------+---------------+---------+---------+-------+------+-------------+
複製代碼
DEPENDENT UNION,UNION中的第二個或後面的SELECT語句,但結果取決於外面的查詢; DEPENDENT SUBQUERY,子查詢中的第一個SELECT,但結果取決於外面的查詢:
mysql> explain select * from employee where id in (select id from employee where id =1 union all select id from employee where id=2);
+----+--------------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
| 1 | PRIMARY | employee | ALL | NULL | NULL | NULL | NULL | 26 | Using where |
| 2 | DEPENDENT SUBQUERY | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | Using index |
| 3 | DEPENDENT UNION | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | Using index |
| NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------------+------------+-------+---------------+---------+---------+-------+------+-----------------+
複製代碼
派生表的SELECT,FROM子句的子查詢:
mysql> explain select * from (select * from employee where id =1) a ;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL |
| 2 | DERIVED | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | NULL |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
複製代碼
type表示數據訪問/讀取的操做類型,顯示了鏈接使用了哪一種類別,有無使用索引,它提供了判斷查詢是否高效的重要依據依據。
常見的類型有經常使用有,性能從差到好排序:ALL, index, range, ref, eq_ref, const, system, NULL
不用訪問表或者索引就能夠直接獲得結果:
mysql> explain select sysdate();
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
複製代碼
如將主鍵或者惟一索引置於where列表中,MySQL就能將該查詢轉換爲一個常量,當表中只有一行記錄時,類型爲system。
mysql> explain select * from (select id from mcc_inform where id =1) a;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL |
| 2 | DERIVED | employee | const | PRIMARY | PRIMARY | 8 | const | 1 | Using index |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+
複製代碼
此類型一般出如今多表的 join 查詢, 表示對於前表的每個結果, 都只能匹配到後表的一行結果. 而且查詢的比較操做一般是 =, 查詢效率較高:
mysql> explain select * from t3,t4 where t3.id=t4.accountid;
+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+
| 1 | SIMPLE | t4 | ALL | NULL | NULL | NULL | NULL | 1000 | |
| 1 | SIMPLE | t3 | eq_ref | PRIMARY,idx_t3_id | idx_t3_id | 4 | dbatest.t4.accountid | 1 | |
+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+
複製代碼
與eq_ref相似,不一樣的是ref不是惟一索引,此類型一般出如今多表的 join 查詢, 針對於非惟一或非主鍵索引, 或者是使用了最左前綴規則索引的查詢,能夠用於使用=或<=>操做符的帶索引的列:
該聯接類型表示使用了索引合併優化方法, where中可能有多個條件(或者join)涉及到多個字段,它們之間進行 AND 或者 OR,那麼此時就有可能會使用到 index merge 技術。
index merge 技術若是簡單的說,其實就是:對多個索引分別進行條件掃描,而後將它們各自的結果進行合併(intersect/union)。
表示使用索引範圍查詢, 經過索引字段範圍獲取表中部分數據記錄, 這個類型一般出如今 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操做中
表示全索引掃描(full index scan), 和 ALL 類型相似, 只不過 ALL 類型是全表掃描, 而 index 類型則僅僅掃描全部的索引, 而不掃描數據。
表示全表掃描, 這個類型的查詢是性能最差的查詢之一,通常不會出現。
EXplain中的不少額外的信息會在Extra字段顯示,此字段可以給出讓咱們深刻理解執行計劃進一步的細節信息,介紹下常見的幾個。
在查找使用索引的狀況下,須要回表去查詢所需的數據。
表示查詢在索引樹中就可查找所需數據, 不用掃描表數據文件, 說明性能不錯。
當SQL中包含ORDER BY 操做,並且沒法利用索引完成排序操做的時候,查詢優化器不得不選擇相應的排序算法來實現。
filesort主要用於查詢數據結果集的排序操做,首先MySQL會使用sort_buffer_size大小的內存進行排序,若是結果集超過了sort_buffer_size大小,會把這一個排序後的chunk轉移到file上,最後使用多路歸併排序完成全部數據的排序操做。
filesort只能應用在單個表上,若是有多個表的數據須要排序,那麼MySQL會先使用using temporary保存臨時數據,而後再在臨時表上使用filesort進行排序,最後輸出結果。
查詢有使用臨時表, 通常出現於排序, 分組和多表join的狀況, 查詢效率不高, 建議優化.
下一篇文章會介紹索引優化原則以及案例分析。
參考文章:
歡迎掃描下方二維碼,關注個人我的微信公衆號,查看更多文章 ~