天天看點

MySQL進階知識(四)——Explain

前言:explain(執行計劃),使用explain關鍵字可以模拟優化器執行sql查詢語句,進而知道MySQL是如何處理sql語句。explain主要用于分析查詢語句或表結構的性能瓶頸。

注:本系列随筆如無特殊說明都MySQL版本都為5.7.22。

1.explain的作用

通過explain+sql語句可以知道如下内容:

①表的讀取順序。(對應id)

②資料讀取操作的操作類型。(對應select_type)

③哪些索引可以使用。(對應possible_keys)

④哪些索引被實際使用。(對應key)

⑤表直接的引用。(對應ref)

⑥每張表有多少行被優化器查詢。(對應rows)

2.explain包含的資訊

explain使用:explain+sql語句,通過執行explain可以獲得sql語句執行的相關資訊。

MySQL進階知識(四)——Explain

下面對explain的表頭字段含義進行解釋。

注:下圖中有些explain表頭不包含partitions和filtered字段,是因為有些截圖是直接從視訊資料中截取的,當并不影響我們的分析。

①id

select查詢的序列号,包含一組數字,表示查詢中執行select子句或操作表的順序,該字段通常與table字段搭配來分析。

#1.id相同,執行順序從上到下。

MySQL進階知識(四)——Explain

id相同,執行順序從上到下,搭配table列進行觀察可知,執行順序為t1->t3->t2。

#2.id不同,如果是子查詢,id的序号會遞增,id值越大執行優先級越高。

MySQL進階知識(四)——Explain

如果是子查詢id的序号會遞增,id值越大執行優先級越高,搭配table列可知,執行順序為t3->t1->t2。

#3.id相同不同,同時存在。

MySQL進階知識(四)——Explain

id如果相同,可認為是同一組,執行順序從上到下。在所有組中,id值越大執行優先級越高。是以執行順序為t3->derived2(衍生表,也可以說臨時表)->t2。

總結:id的值表示select子句或表的執行順序,id相同,執行順序從上到下,id不同,值越大的執行優先級越高。

②select_type

查詢的類型,主要用于差別普通查詢、聯合查詢、子查詢等複雜的查詢。其值主要有六個:

#1.SIMPLE

簡單的select查詢,查詢中不包含子查詢或union查詢。

#2.PRIMARY

查詢中若包含任何複雜的子部分,最外層查詢為PRIMARY,也就是最後加載的就是PRIMARY。

#3.SUBQUERY

在select或where清單中包含了子查詢,就為被标記為SUBQUERY。

#4.DERIVED

在from清單中包含的子查詢會被标記為DERIVED(衍生),MySQL會遞歸執行這些子查詢,将結果放在臨時表中。

#5.UNION

若第二個select出現在union後,則被标記為UNION,若union包含在from子句的子查詢中,外層select将被标記為DERIVED。

#6.UNION RESULT

從union表擷取結果的select。

MySQL進階知識(四)——Explain

③table

顯示sql操作屬于哪張表的。

④partitions

官方定義為The matching partitions(比對的分區),該字段應該是看table所在的分區吧(不曉得了解錯誤沒)。值為NULL表示表未被分區。

⑤type

表示查詢所使用的通路類型,type的值主要有八種,該值表示查詢的sql語句好壞,從最好到最差依次為:system>const>eq_ref>ref>range>index>ALL。

要詳細了解type取值的作用,需要用資料說話。建立tb_emp(員工表)和tb_dept(部門表)。

a)tb_emp表。

DROP TABLE IF EXISTS `tb_emp`;
CREATE TABLE `tb_emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `deptid` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_tb_emp_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `tb_emp`(name,deptid) VALUES ('jack', '1');
INSERT INTO `tb_emp`(name,deptid) VALUES ('tom', '1');
INSERT INTO `tb_emp`(name,deptid) VALUES ('tonny', '1');
INSERT INTO `tb_emp`(name,deptid) VALUES ('mary', '2');
INSERT INTO `tb_emp`(name,deptid) VALUES ('rose', '2');
INSERT INTO `tb_emp`(name,deptid) VALUES ('luffy', '3');
INSERT INTO `tb_emp`(name,deptid) VALUES ('outman', '4');      

b)tb_dept表。

DROP TABLE IF EXISTS `tb_dept`;
CREATE TABLE `tb_dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `deptname` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `tb_dept`(deptname) VALUES ('研發');
INSERT INTO `tb_dept`(deptname) VALUES ('測試');
INSERT INTO `tb_dept`(deptname) VALUES ('運維');
INSERT INTO `tb_dept`(deptname) VALUES ('經理');      

#1.system

表隻有一行記錄(等于系統表),是const的特例類型,平時不會出現,可以忽略不計。

但是筆者發現在MySQL5.7.22時,不會出現該字段值,隻能出現const,但是在MySQL5.7版本以下可以出現該情況。猜測MySQL5.7版本是不是進行了優化,因為system官網的解釋:

MySQL進階知識(四)——Explain

5.5.48:

MySQL進階知識(四)——Explain

5.7.22:

MySQL進階知識(四)——Explain

注:兩個引擎的執行資訊不一樣,5.5.48執行過程中産生了臨時表(DERIVED),5.7.22為簡單查詢。

#2.const

表示通過一次索引就找到了結果,常出現于primary key或unique索引。因為隻比對一行資料,是以查詢非常快。如将主鍵置于where條件中,MySQL就能将查詢轉換為一個常量。

MySQL進階知識(四)——Explain

注:對于system和const可能實際意義并不是很大,因為單表單行查詢本來就快,意義不大。

#3.eq_ref

唯一索引掃描,對于每個索引鍵,表中隻有一條記錄與之比對。常見主鍵或唯一索引掃描。

MySQL進階知識(四)——Explain

注:經理隻有一人,進行了tb_dept的主鍵掃描。

#4.ref

非唯一性索引掃描,傳回比對某個單獨值的所有行。本質上也是一種索引通路,傳回比對某值(某條件)的多行值,屬于查找和掃描的混合體。

由于是非唯一性索引掃描,是以對tb_emp表的deptid字段建立索引:

create index idx_tb_emp_deptid on tb_emp(deptid);      
MySQL進階知識(四)——Explain

#5.range

隻檢索給定範圍的行,使用一個索引來檢索行,可以在key列中檢視使用的索引,一般出現在where語句的條件中,如使用between、>、<、in等查詢。

這種索引的範圍掃描比全索引掃描要好,因為索引的開始點和結束點都固定,範圍相對較小。

MySQL進階知識(四)——Explain

雖然我們為deptid字段建立了索引并在where中使用了between等,但在如下情況type仍為ALL。

MySQL進階知識(四)——Explain
MySQL進階知識(四)——Explain

對比兩圖,可以看到使用deptid和id進行操作,其type的值一個是ALL也就是進行了全表掃描,一個是range進行了指定索引範圍值檢索。可能原因deptid并不是唯一索引。

對于以上問題,需要具體問題具體分析,并不能一概而論。

#6.index

全索引掃描,index和ALL的差別:index隻周遊索引樹,通常比ALL快,因為索引檔案通常比資料檔案小。雖說index和ALL都是全表掃描,但是index是從索引中讀取,ALL是從磁盤中讀取。

MySQL進階知識(四)——Explain

#7.ALL

全表掃描。

注:一般來說,需保證查詢至少達到range級别,最好能達到ref。

⑥possible_keys和key、key_len

possible_keys:顯示可能應用在表中的索引,可能一個或多個。查詢涉及到的字段若存在索引,則該索引将被列出,但不一定被查詢實際使用。

key:實際中使用的索引,如為NULL,則表示未使用索引。若查詢中使用了覆寫索引,則該索引和查詢的select字段重疊。

key_len:表示索引中所使用的位元組數,可通過該列計算查詢中使用的索引長度。在不損失精确性的情況下,長度越短越好。key_len顯示的值為索引字段的最大可能長度,并非實際使用長度,即key_len是根據表定義計算而得,并不是通過表内檢索出的。

簡單了解:possible_keys表示理論上可能用到的索引,key表示實際中使用的索引。

MySQL進階知識(四)——Explain

possible_keys為NULL表示可能未用到索引,但key=idx_deptid表示在實際查詢的過程中進行了索引的全掃描。

通過下面的例子來了解key_len,首先為name字段建立索引:

create index idx_name on tb_emp(name);      
MySQL進階知識(四)——Explain

注:在使用索引查詢時,當條件越精确,key_len的長度可能會越長,是以在不影響結果的情況下,key_len的值越短越好。

⑦ref

顯示關聯的字段。如果使用常數等值查詢,則顯示const,如果是連接配接查詢,則會顯示關聯的字段。

MySQL進階知識(四)——Explain

注:由于id相同,是以從上到下執行:

#1.tb_emp表為非唯一性索引掃描,實際使用的索引列為idx_name,由于tb_emp.name='rose'為一個常量,是以ref=const。

#2.tb_dept為唯一索引掃描,從sql語句可以看出,實際使用了PRIMARY主鍵索引,ref=db01.tb_emp.deptid表示關聯了db01資料庫中tb_emp表的deptid字段。

⑧rows

根據表統計資訊及索引選用情況大緻估算出找到所需記錄所要讀取的行數。當然該值越小越好。

⑨filtered

百分比值,表示存儲引擎傳回的資料經過濾後,剩下多少滿足查詢條件記錄數量的比例。

⑩Extra

顯示十分重要的額外資訊。其取值有以下幾個:

#1.Using filesort

Using filesort表明mysql會對資料使用一個外部的索引排序,而不是按照表内的索引順序進行讀取。

mysql中無法利用索引完成的排序操作稱為“檔案排序”。

出現Using filesort就非常危險了,在資料量非常大的時候幾乎“九死一生”。出現Using filesort盡快優化sql語句。

deptname字段未建索引的情況。

MySQL進階知識(四)——Explain

為deptname字段建立索引後。

MySQL進階知識(四)——Explain

#2.Using temporary

使用了臨時表儲存中間結果,常見于排序order by和分組查詢group by。非常危險,“十死無生”,急需優化。

将tb_emp中name的索引先删除,出現如下圖結果,非常爛,Using filesort和Using temporary,“十死無生”。

MySQL進階知識(四)——Explain

為name字段建立索引後。

MySQL進階知識(四)——Explain

#3.Using index

表明相應的select操作中使用了覆寫索引,避免通路表的額外資料行,效率不錯。

如果同時出現了Using where,表明索引被用來執行索引鍵值的查找。(where deptid=1)

如果沒有同時出現Using where,表明索引用來讀取資料而非執行查找動作。

删除tb_emp表中name和deptid字段的單獨索引,建立複合索引。

MySQL進階知識(四)——Explain

從這裡給出覆寫索引的定義:select的資料列隻從索引中就能取得資料,不必讀取資料行。通過上面的例子了解:建立了(name,deptid)的複合索引,查詢的時候也使用複合索引或部分,這就形成了覆寫索引。簡記:查詢使用複合索引,并且查詢的列就是索引列,不能多,個數需對應。

使用優先級Using index>Using filesort(九死一生)>Using temporary(十死無生)。也就說出現後面兩項表明sql語句是非常爛的,急需優化!!!

總結

explain(執行計劃)包含的資訊十分的豐富,着重關注以下幾個字段資訊。

①id,select子句或表執行順序,id相同,從上到下執行,id不同,id值越大,執行優先級越高。

②type,type主要取值及其表示sql的好壞程度(由好到差排序):system>const>eq_ref>ref>range>index>ALL。保證range,最好到ref。

③key,實際被使用的索引列。

④ref,關聯的字段,常量等值查詢,顯示為const,如果為連接配接查詢,顯示關聯的字段。

⑤Extra,額外資訊,使用優先級Using index>Using filesort(九死一生)>Using temporary(十死無生)。

着重關注上述五個字段資訊,對日常生産過程中調優十分有用。

by Shawn Chen,2018.6.22日,下午。

相關内容

MySQL進階知識系列目錄

=========================================================

比你優秀的人比你還努力,你有什麼資格不去奮鬥!

__一個有理想的程式員。

繼續閱讀