1. 程式人生 > 資料庫 >【mysql 5.7】Explain工具介紹-筆記

【mysql 5.7】Explain工具介紹-筆記

文章目錄

1. Explain工具介紹

使用EXPLAIN關鍵字可以模擬優化器執行SQL語句,分析你的查詢語句或是結構的效能瓶頸在 select 語句之前增加 explain 關鍵字,MySQL 會在查詢上設定一個標記,執行查詢會返回執行計劃的資訊,而不是執行這條SQL注意:如果 from 中包含子查詢,仍會執行該子查詢,將結果放入臨時表中

1.1 Explain分析示例

參考官方文件:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

DROP TABLE IF EXISTS `actor`;
CREATE TABLE `actor` (
  `id` int(11) NOT NULL,
  `name` varchar(45) DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 INSERT INTO `actor` (`id`, `name`, `update_time`) VALUES (1,'a','2017-12-22 15:27:18'), (2,'b','2017-12-22 15:27:18'), (3,'c','2017-12-22 15:27:18');

DROP TABLE IF EXISTS `film`;
CREATE TABLE `film` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

INSERT INTO `film` (`id`, `name`) VALUES (3,'film0'),(1,'film1'),(2,'film2');


 DROP TABLE IF EXISTS `film_actor`;
 CREATE TABLE `film_actor` (
  `id` int(11) NOT NULL,
  `film_id` int(11) NOT NULL,
  `actor_id` int(11) NOT NULL,
  `remark` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_film_actor_id` (`film_id`,`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

INSERT INTO `film_actor` (`id`, `film_id`, `actor_id`) VALUES (1,1,1),(2,1,2),(3,2,1);

EXPLAIN SELECT * FROM actor;

    id  select_type  table   partitions  type    possible_keys  key     key_len  ref       rows  filtered  Extra   
------  -----------  ------  ----------  ------  -------------  ------  -------  ------  ------  --------  --------
     1  SIMPLE       actor   (NULL)      ALL     (NULL)         (NULL)  (NULL)   (NULL)       3    100.00  (NULL)  

在查詢中的每個表會輸出一行,如果有兩個表通過 join 連線查詢,那麼會輸出兩行

1.2 explain 兩個變種

1)explain extended:會在 explain 的基礎上額外提供一些查詢優化的資訊。緊隨其後通過 show warnings 命令可以得到優化後的查詢語句,從而看出優化器優化了什麼。

額外還有 filtered 列,是一個半分比的值,rows * filtered/100可以估算出將要和 explain 中前一個表進行連線的行數(前一個表指 explain 中的id值比當前表id值小的表)。

將要被廢棄,比如5.7,不帶extended,預設就會顯示filtered 列

show warnings 命令可以在任意sql語句之後,不必要非在Explain之後,比如檢視時間 SELECT NOW();

執行一下語句:

EXPLAIN EXTENDED SELECT * FROM film WHERE id = 1;

執行結果:

    id  select_type  table   partitions  type    possible_keys  key      key_len  ref       rows  filtered  Extra   
------  -----------  ------  ----------  ------  -------------  -------  -------  ------  ------  --------  --------
     1  SIMPLE       film    (NULL)      const   PRIMARY        PRIMARY  4        const        1    100.00  (NULL)  
                                                                                                                    

執行:

show warnings;

執行結果:
在這裡插入圖片描述
2)explain partitions:相比 explain 多了個 partitions 欄位,如果查詢是基於分割槽表的話,會顯示查詢將訪問的分割槽。

作用不大。5.7版本預設攜帶partitions 欄位

2. explain中的列

接下來我們將展示 explain 中每個列的資訊。

2.1 id列

id列的編號是 select 的序列號,有幾個 select 就有幾個id,並且id的順序是按 select 出現的順序增長的。
id列越大執行優先順序越高,id相同則從上往下執行,id為NULL最後執行。

對子查詢包括父查詢,進行編號

2.2 select_type列

select_type 表示對應行是簡單還是複雜的查詢。

simple:簡單查詢。

查詢不包含子查詢和union

mysql> explain select * from film where

在這裡插入圖片描述

primary

複雜查詢中最外層的 select

subquery

包含在 select 中的子查詢(不在 from 子句中

derived:

包含在 from 子句中的子查詢。MySQL會將結果存放在一個臨時表中,也稱為派生表(derived的英文含義)

用這個例子來了解 primary、subquery 和 derived 類:

mysql> set session optimizer_switch='derived_merge=off'; #關閉mysql5.7新特性對衍生表的合併優化
mysql> explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;

注意:需要關閉mysql5.7新特性對衍生表的合併優化

在這裡插入圖片描述

還原預設配置:

mysql> set session optimizer_switch='derived_merge=on'; #還原預設配置

union:

在 union 中的第二個或後面的 select

mysql> explain select 1 union all select 1;

在這裡插入圖片描述

2.3. table列

這一列表示 explain 的一行正在訪問哪個表。

類似一個指標,指向某個表,如果表的位置是個子句,那麼就是子句的下標

當 from 子句中有子查詢時,table列是 <derivenN> 格式,表示當前查詢依賴 id=N 的查詢,於是先執行 id=N 的查詢。

參見derived:章節的例子:
在這裡插入圖片描述

當有 union 時,UNION RESULT 的 table 列的值為<union1,2>,1和2表示參與 union 的 select 行id。

2.4. type列

這一列表示關聯型別或訪問型別,即MySQL決定如何查詢表中的行,查詢資料行記錄的大概範圍。

依次從最優到最差分別為:system > const > eq_ref > ref > range > index > ALL

一般來說,得保證查詢達到range級別,最好達到ref

2.4.1 NULL

mysql能夠在優化階段分解查詢語句,在執行階段用不著再訪問表或索引。例如:在索引列中選取最小值,可以單獨查詢索引來完成,不需要在執行時訪問表

mysql> explain select min(id) from film;

在這裡插入圖片描述

2.4.2 const, system:

mysql能對查詢的某部分進行優化並將其轉化成一個常量(可以看show warnings 的結果)。

用於primary keyunique key 的所有列與常數比較時,所以表最多有一個匹配行,讀取1次,速度比較快。

system是const的特例,表裡只有一條元組匹配時為system

mysql> SET SESSION optimizer_switch='derived_merge=off'
mysql> explain extended select * from (select * from film where id = 1) tmp;

在這裡插入圖片描述

mysql> show warnings;

在這裡插入圖片描述

2.4.2 eq_ref

primary keyunique key 索引的所有部分被連線使用 ,最多隻會返回一條符合條件的記錄。這可能是在const 之外最好的聯接型別了,簡單的 select 查詢不會出現這種 type

mysql> explain select * from film_actor left join film on film_actor.film_id = film.id;

參考:

參考主體