性能優化是一個開發或者dba不可少的工做內容,工欲善其事必先利其器,本文介紹一個輔助咱們查看sql執行計劃是否優化的工具,經過explain的結果,咱們能夠肯定sql是否利用正確的索引。sql
MySQL 5.7數據庫
create table a( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL DEFAULT '', age INT(11) DEFAULT 0, primary key (id), key idx_name (name)) engine = innodb default charset= utf8;insert into a (name, age) values('yy', 11);insert into a (name, age) values('xx', 25);insert into a (name, age) values('yz', 23);insert into a (name, age) values('zhangcan', 32);insert into a (name, age) values('lisi', 18);insert into a (name, age) values('boshi', 62);insert into a (name, age) values('taisen', 52);insert into a (name, age) values('liuxiang', 32);insert into a (name, age) values('malong', 23);insert into a (name, age) values('jingtian', 28);create table b( id bigint(20) NOT NULL AUTO_INCREMENT, sid int not null default 0, name varchar(50) NOT NULL DEFAULT '', score INT(11) DEFAULT 0, primary key (id), key idx_sid(sid), key idx_name (name)) engine = innodb default charset= utf8;insert into b (sid,name, score) values(1,'yy', 99);insert into b (sid,name, score) values(1,'yy', 99);insert into b (sid,name, score) values(1,'yy', 99);insert into b (sid,name, score) values(2,'xx', 95);insert into b (sid,name, score) values(2,'xx', 95);insert into b (sid,name, score) values(3,'yz', 93);insert into b (sid,name, score) values(3,'yz', 93);insert into b (sid,name, score) values(4,'zhangcan', 90);insert into b (sid,name, score) values(5,'lisi', 88);insert into b (sid,name, score) values(5,'lisi', 80);insert into b (sid,name, score) values(5,'lisi', 78);insert into b (sid,name, score) values(6,'boshi', 83);insert into b (sid,name, score) values(6,'boshi', 80);insert into b (sid,name, score) values(6,'boshi', 92);insert into b (sid,name, score) values(7,'taisen', 85);insert into b (sid,name, score) values(8,'liuxiang', 81);insert into b (sid,name, score) values(9,'malong', 92);insert into b (sid,name, score) values(10,'jingtian', 78);insert into b (sid,name, score) values(10,'jingtian', 90);insert into b (sid,name, score) values(10,'jingtian', 88);insert into b (sid,name, score) values(10,'jingtian', 93);複製代碼
執行 explian 的結果以下:性能優化
test >explain select * from a where id=3 \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: a partitions: NULL type: constpossible_keys: PRIMARY key: PRIMARY key_len: 8 ref: const rows: 1 filtered: 100.00 Extra: NULL複製代碼
從上面的輸出咱們能夠看到,分別是id、type、tabl、selecttype、possiblekeys、key、key_len、ref、rows、Extra。本文主要以select語句爲例講解 explian的輸出。bash
查詢語句的序號或者說是標識符,每一個查詢語句包括子查詢都會分配一個id,表示查詢中執行select子句或者操做表的順序,可能有以下幾種狀況併發
1 id值相同高併發
id 值相同通常出如今多表關聯的場景,訪問表的順序是從上到下 。工具
兩個id 都爲1,先訪問b表而後訪問a表。性能
2 id值不一樣測試
id 值不一樣的狀況,從大到小執行,值越大越先開始執行或者被訪問。優化
從結果來看,id爲2 那一行的子查詢先被執行。而後再去訪問id=1 中a表。
思考題 若是 a.id in (select sid from b where id=10); explai的結果會是什麼樣呢?
3 id 包含了相同和不一樣的狀況。
該狀況通常是現有2個表或者子查詢和表join ,而後在和第三個表關聯查詢。好比
EXPLAIN SELECT t2.* FROM(SELECT t3.id FROM t3 WHERE t3.other_column = '') s1,t2 WHERE s1.id = t2.id;+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | || 1 | PRIMARY | t2 | const | PRIMARY | PRIMARY | 4 | const | 1 | || 2 | DERIVED | t3 | ALL | NULL | NULL | NULL | NULL | 5 | Using where |+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+複製代碼
分析結果可看出,先走id最大的2,也就是先走括號裏面的查t3表的語句。走完查t3後,順序執行,有一個,derived是衍生的意思,意思是在執行完t3查詢後的s1虛表基礎上,中的2,就是id爲2的。最後執行的查t2表。
5.7的優化器針對子查詢作了不少優化,我本身沒有模擬出來場景3,故使用網上的例子。
常見的有以下6種:SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION、UNION RESULT,主要是告訴咱們查詢的類型是普通查詢、聯合查詢、子查詢等複雜的查詢。
SIMPLE:最簡單的查詢,查詢中不包含子查詢或者UNION。
PRIMARY:查詢中若包含任何複雜的子查詢,最外層查詢則被標記爲PRIMARY,也就是最後被執行的語句。
SUBQUERY:在SELECT from 或者WHERE列表中包含了子查詢
DERIVED:在FROM列表中包含的子查詢被標記爲DERIVED(衍生)MySQL會遞歸執行這些子查詢,把結果放在臨時表裏。
UNION:若第二個SELECT出如今UNION以後,則被標記爲UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲DERIVED
UNION RESULT:兩種UNION語句的合併。
DEPENDENT SUBQUERY: 子查詢中的第一個 SELECT, 取決於外面的查詢. 即子查詢依賴於外層查詢的結果. 出現該值的時候必定要特別注意,可能須要使用join的方式優化子查詢。
其值爲表名或者表的別名,表示訪問哪個表,
當from中有子查詢的時候,表名是derivedN的形式,其中 N 指向子查詢,也就是explain結果中的下一列
當有union result的時候,表名是union 1,2等的形式,1,2表示參與union的query id
注意 MySQL對待這些表和普通表同樣,可是這些臨時表是沒有任何索引的。數據量大的狀況下可能會有性能問題。
從最好到最差的結果依次以下:
system > const > eq_ref > ref > range > index > ALL
system: 表示結果集僅有一行。這是const聯接類型的一個特例,表須是myisam或者memory存儲引擎。若是是innodb存儲引擎,type 顯示爲 const 。
const: 表示經過主鍵或者惟一鍵鍵查找數據時只匹配最多一行數據。
eq_ref: 該類型多出如今多表join場景,經過主鍵或者惟一鍵訪問表.
對於前表b的每行記錄, 都只能匹配到後表a的一行記錄而且查詢的比較操做一般是 =,查詢效率較高.
ref: 此類型一般出如今sql使用非惟一或非主鍵索引, 或者是使用最左前綴規則索引的查詢. 例以下面這個例子中, 就使用到了 ref 類型的查詢:
range: 表示where條件使用索引範圍查詢, 經過索引字段範圍獲取表中部分數據記錄. 這個類型一般出如今 <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操做中.當 type 是 range 時,ref 字段爲 NULL。
index: 表示全索引掃描(full index scan), 和 ALL 類型相似,只不過 ALL 類型是全表掃描, 而 index 類型則是掃描全部的索引記錄, 而不掃描數據。
index 類型一般會出如今覆蓋索引中,所要查詢的數據直接在索引中就能夠訪問, 而不用回表掃描數據. 此時Extra 字段 會顯示 Using index。
還有一種是全表掃描時經過索引順序訪問數據。此時並不會在Extra提示 using index。
ALL: 表示執行計劃選擇全表掃描,除非數據量極少好比100之內(別擡槓問'101能夠嗎',遇到太高併發count 1000行數據把數據庫堵住的),當執行計劃出現type 爲all 時,咱們儘可能經過修改索引的方式讓查詢利用索引。
possible_keys 表示 MySQL 在查詢時, 可以使用到的索引. 注意, 即便有些索引在 possible_keys 中出現,可是並不表示此索引會真正地被 MySQL 使用到. MySQL 在查詢時具體使用了哪些索引, 由 key 字段決定。
此字段是 MySQL 在當前查詢時所真正使用到的索引。
key_len表示執行計劃所選擇的索引長度有多少字節,一般咱們可藉此判斷聯合索引有多少列被選擇
在這裏 key_len 大小的計算規則是:
通常地,key_len 等於索引列類型字節長度,例如int類型爲4 bytes,bigint爲8 bytes;
若是是字符串類型,還須要同時考慮字符集因素,例如:CHAR(30) UTF8則key_len至少是90 bytes;
若該列類型定義時容許NULL,其key_len還須要再加 1 bytes;
若該列類型爲變長類型,例如 VARCHAR(TEXT\BLOB不容許整列建立索引,若是建立部分索引也被視爲動態列類型),其key_len還須要再加 2 bytes;
id 爲bigint 是8個字節 故key_len=8
表a的字符集爲utf8,name='lisi' name 爲varchar(50) key_len=50*3+2=152 。
rows 也是一個重要的字段。 MySQL 查詢優化器根據統計信息,估算 SQL 要查找到結果集須要掃描讀取的數據行數。原則上 rows 越少越好。記住這個並不是是徹底準確的值。
顧名思義 ,該列會提示優化執行計劃的額外的信息,值得你們關注的有以下幾種:
Using index
當 extra 中出現 Using index 時,表示該sql利用覆蓋索引掃描,也即從只訪問索引便可獲取到所需的數據,而不用回表。
Using where
當 extra 中出現 Using where時,表示該sql 回表獲取數據了。什麼是回表呢? 其實就是僅僅經過訪問索引不能知足獲取所需的數據,須要訪問表的page 頁。
若是和Using index 同時出現,說明where條件經過索引定位數據,而後回表,再過濾所須要的數據。
Using filesort
出現 using filesort 說明排序沒有利用索引而發生了額外排序 ,伴隨着的可能還有Using temporary; Using filesort 同時用到臨時表排序。
其實還有其餘一些 提示 Using MRR,Using index condition ,Using index for group-by 等這些提示是正向的,說明sql比較優化。
本文基於案例解釋如何理解explain的執行結果,但願對各位須要評估sql執行計劃的朋友有所幫助。