MySQL進階系列: 一文詳解explain各字段含義

這是我參與8月更文挑戰的第2天,活動詳情查看:8月更文挑戰mysql

explain有何用處呢:爲了知道優化SQL語句的執行,須要查看SQL語句的具體執行過程,以加快SQL語句的執行效率。算法

可使用explain+SQL語句來模擬優化器執行SQL查詢語句,從而知道mysql是如何處理sql語句的。經過查看執行計劃瞭解執行器是否按照咱們想的那樣處理SQL。sql

explain執行計劃中包含的信息以下:數據庫

  • id:  查詢序列號
  • select_type: 查詢類型
  • table: 表名或者別名
  • partitions: 匹配的分區
  • type: 訪問類型
  • possible_keys: 可能用到的索引
  • key: 實際用到的索引
  • key_len: 索引長度
  • ref: 與索引比較的列
  • rows: 估算的行數
  • filtered: 按表條件篩選的行百分比
  • Extra: 額外信息

下面說下具體每一列的表示的含義和對應sql.緩存

測試使用mysql版本5.7, 使用的3個表結構以下markdown

CREATE TABLE `demo`.`emp`  (
  `emp_id` bigint(20) NOT NULL,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '姓名',
  `empno` int(20) NOT NULL COMMENT '工號',
  `deptno` int(20) NOT NULL COMMENT '部門編號',
  `sal` int(11) NOT NULL DEFAULT 0 COMMENT '銷售量',
  PRIMARY KEY (`emp_id`) USING BTREE,
  INDEX `u1`(`deptno`) USING BTREE,
  UNIQUE INDEX `u2`(`empno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;

CREATE TABLE `demo`.`dept`  (
  `id` bigint(20) NOT NULL,
  `deptno` int(20) NOT NULL COMMENT '部門編碼',
  `dname` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '部門名稱',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `dept_u1`(`deptno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;


CREATE TABLE `demo`.`salgrade`  (
  `id` bigint(20) NOT NULL,
  `losal` int(20) NULL DEFAULT NULL,
  `hisal` int(20) NULL DEFAULT NULL,
  `emp_id` bigint(20) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
複製代碼

一 id列

select查詢的序列號(一組數字),表示查詢中執行select子句或者操做表的順序。架構

id列分爲三種狀況:數據庫設計

一、若是id相同,那麼執行順序從上到下post

mysql> explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.losal and sg.hisal;
複製代碼

二、若是id不一樣,若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行\性能

mysql> explain select * from emp e where e.deptno = (select d.deptno from dept d where d.dname = 'SALES');
複製代碼

三、id相同和不一樣的,同時存在:相同的能夠認爲是一組,從上往下順序執行,在全部組中,id值越大,優先級越高,越先執行

mysql> explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.losal and sg.hisal wheree.deptno = (select d.deptno from dept d where d.dname = 'SALES');
複製代碼

二,select_type列

主要用來分辨查詢的類型,是普通查詢仍是聯合查詢仍是子查詢
複製代碼

1. sample: 簡單的查詢,不包含子查詢和union

mysql> explain select * from emp;
複製代碼

  1. primary: 查詢中若包含任何複雜的子查詢,最外層查詢則被標記爲Primary
mysql> explain select * from emp e where e.deptno = (select d.deptno from dept d where d.dname = 'SALES');
複製代碼

  1. union: 在union,union all和子查詢中的第二個和隨後的select被標記爲union
mysql> explain select * from emp where deptno = 10 union select * from emp where sal >2000;
複製代碼

4. dependent union: 在包含UNION或者UNION ALL的大查詢中,若是各個小查詢都依賴於外層查詢的話,那除了最左邊的那個小查詢以外,其他的小查詢的select_type的值就是DEPENDENT UNION。

mysql> explain select * from emp e where e.empno  in ( select empno from emp where deptno = 10 union select empno from emp where sal >2000)
複製代碼

5. union result: 從union表獲取結果的select。

mysql> explain select * from emp where deptno = 10 union select * from emp where sal >2000;
複製代碼

6. subquery: 在select或者where列表中包含子查詢(不在from子句中)

mysql> explain select * from emp where sal > (select avg(sal) from emp) ;
複製代碼

7. dependent subquery: 子查詢中的第一個select(不在from子句中),並且取決於外面的查詢。

mysql> explain select e1.* from emp e1 WHERE e1.deptno = (SELECT deptno FROM emp e2 WHERE e1.empno = e2.empno);
複製代碼

8. derived: ****在FROM列表中包含的子查詢被標記爲DERIVED,也叫作派生類

mysql> explain select * from ( select emp_id,count(*) from emp group by emp_id ) e;
複製代碼

9. UNCACHEABLE SUBQUERY:一個子查詢的結果不能被緩存,必須從新評估外連接的第一行對於外層的主表,子查詢不可被物化,每次都須要計算(耗時操做)

mysql> explain select * from emp where empno = (select empno from emp where deptno=@@sort_buffer_size);
複製代碼

10. uncacheable union: 表示union的查詢結果不能被緩存:沒找到具體的sql語句驗證.

三,table列

對應行正在訪問哪個表,表名或者別名,多是臨時表或者union合併結果集.

    一、若是是具體的表名,則代表從實際的物理表中獲取數據,固然也能夠是表的別名.

    二、表名是derivedN的形式,表示使用了id爲N的查詢產生的衍生表.

    三、當有union result的時候,表名是union n1,n2等的形式,n1,n2表示參與union的id.

四,type列

type顯示的是訪問類型,訪問類型表示我是以何種方式去訪問咱們的數據,最容易想的是全表掃描,直接暴力的遍歷一張表去尋找須要的數據,效率很是低下。

訪問的類型有不少,效率從最好到最壞依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

通常狀況下,要保證查詢至少達到range級別,最好能達到ref

    1. all: 全表掃描,須要掃描整張表,從頭至尾找到須要的數據行。通常狀況下出現這樣的sql語句並且數據量比較大的話那麼就須要進行優化。

mysql> explain select * from emp;
複製代碼

    2. index:全索引掃描這個比all的效率要好,主要有兩種狀況,一種是當前的查詢時覆蓋索引,即咱們須要的數據在索引中就能夠索取,或者是使用了索引進行排序,這樣就避免數據的重排序

mysql> explain  select empno from emp;
複製代碼

    3. range:表示利用索引查詢的時候限制了範圍,在指定範圍內進行查詢,這樣避免了index的全索引掃描,適用的操做符:=, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN() 

mysql> explain select * from emp where empno between 100 and 200;
複製代碼

    4. index_subquery:利用索引來關聯子查詢,再也不掃描全表

mysql> explain select * from emp where deptno not in (select deptno from emp)
複製代碼

可是大多數狀況下使用SELECT子查詢時,MySQL查詢優化器會自動將子查詢優化爲聯表查詢,所以 type 不會顯示爲 index_subquery,而是ref

    5. unique_subquery: 該鏈接類型相似於index_subquery,使用的是惟一索引

mysql> explain SELECT * from emp where emp_id not in (select emp.emp_id from emp );
複製代碼

大多數狀況下使用SELECT子查詢時,MySQL查詢優化器會自動將子查詢優化爲聯表查詢,所以 type 不會顯示爲 index_subquery,而是eq_ref

    6. index_merge:在查詢過程當中須要多個索引組合使用.

mysql> 沒有模擬出來

    7. ref_or_null:對於某個字段即須要關聯條件,也須要null值的狀況下,查詢優化器會選擇這種訪問方式.

mysql> 沒模擬出來

    8. ref:使用了非惟一性索引進行數據的查找

mysql> explain select * from emp where  deptno=10;
複製代碼

    9. eq_ref :當進行等值聯表查詢使用主鍵索引或者惟一性非空索引進行數據查找(實際上惟一索引等值查詢type不是eq_ref而是const)

mysql> explain select * from salgrade s LEFT JOIN emp e on s.emp_id = e.emp_id;
複製代碼

    10. const:最多隻能匹配到一條數據,一般使用主鍵或惟一索引進行等值條件查詢

mysql> explain select * from emp where empno = 10;
複製代碼

    11. system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現,不須要進行磁盤io

mysql> explain SELECT * FROM `mysql`.`proxies_priv`;
複製代碼

五,possible_keys列

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

六,key列

實際使用的索引,若是爲null,則沒有使用索引,查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊。

七,key_len列

表示索引中使用的字節數,能夠經過key_len計算查詢中使用的索引長度,在不損失精度的狀況下長度越短越好。

索引越大佔用存儲空間越大,這樣io的次數和量就會增長,影響執行效率

八,ref列

顯示以前的表在key列記錄的索引中查找值所用的列或者常量

九,rows列

根據表的統計信息及索引使用狀況,大體估算出找出所需記錄須要讀取的行數,此參數很重要,直接反應的sql找了多少數據,在完成目的的狀況下越少越好。

十,filtered列

針對表中符合某個條件(where子句或者聯接條件)的記錄數的百分比所作的一個悲觀估算。

十一,extra列

包含額外的信息。

    1. using filesort: 說明mysql沒法利用索引進行排序,只能利用排序算法進行排序,會消耗額外的位置

mysql> explain select * from emp order by sal;
複製代碼

    2. using temporary: 創建臨時表來保存中間結果,查詢完成以後把臨時表刪除

mysql> explain select name,count(*) from emp where deptno = 10 group by name;
複製代碼

        3. using index: 這個表示當前的查詢是覆蓋索引的,直接從索引中讀取數據,而不用訪問數據表。若是同時出現using where 表名索引被用來執行索引鍵值的查找,若是沒有,表面索引被用來讀取數據,而不是真的查找

mysql> explain select deptno,count(*) from emp group by deptno limit 10;
複製代碼

    4. using where: 使用where進行條件過濾

mysql> explain select * from emp where name = 1;
複製代碼

    5. using join buffer: 使用鏈接緩存

mysql> explain select * from emp e left join dept d on e.deptno = d.deptno;
複製代碼

    6. impossible where:where語句的結果老是false

mysql> explain select * from emp where 1=0;
複製代碼

文中有問題的能夠給我留言,部分沒有模擬出來的也能夠給意見

參考《高性能MySQL》

mysql進階系列歷史回顧:

1. 基礎架構篇

2. 存儲引擎

3. MyISAM和InnoDB有什麼區別篇

4. 表設計如何更好的選擇數據類型

5. 數據庫設計中的範式究竟該如何使用

相關文章
相關標籤/搜索