mysql explain实践
前言
使用EXPLAIN關鍵字可以模擬優化器執行SQL語句,從而知道MySQL是如何處理SQL語句的。幫助分析查詢語句或是結構的性能瓶頸。
在 select 語句之前增加 explain 關鍵字,MySQL 會在查詢上設置一個標記,執行查詢時,會返回執行計劃的信息,而不是執行這條SQL(如果 from 中包含子查詢,仍會執行該子查詢,將結果放 入臨時表中)。
數據準備
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 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);實踐(版本:5.7.30)
語法
在select 語句前加 explain 關鍵字。
explain select (select 1 from actor limit 1) from film;輸出:
輸出結果屬性說明
id 列
id列的編號是 select 的序列號,有幾個 select 就有幾個id (不是絕對的,可能會優化),并且id的順序是按 select 出現的順序 增長的。MySQL將 select 查詢分為簡單查詢(SIMPLE)和復雜查詢(PRIMARY)。 復雜查詢分為三類:簡單子查詢、派生表(from語句中的子查詢)、union 查詢。 id列越大執行優先級越高,id相同則從上往下執行,id為NULL最后執行。
示例 1:
explain select id from (select id from film) as der; explain select id + 1 as c from (select id from film) as der; explain select id ,name as c from (select id,name from film) as der;輸出:
說明:3個語句的輸出,都只有1條記錄。由于第1個select查詢的 id 列在派生表中,并且是同一個表,所以優化后,僅顯示1條記錄。
select_type 列
select_type 表示對應行是簡單還是復雜的查詢,如果是復雜的查詢,又是上述三種復雜查詢中的哪一種。
1)、SIMPLE。前面已有示例。
2)、PRIMARY:復雜查詢中最外層的 select
3)、SUBQUERY:包含在 select 部分的子查詢(不在 from 子句中)
4)、DERIVED:包含在 from 子句中的子查詢。MySQL會將結果存放在一個臨時表中,也稱為派生 表。
5)、UNION:在 union 語句中的第二個union 和隨后的 select語句
6)、DEPENDENT SUBQUERY:表示這個subquery的查詢要受到外部表查詢的影響。where 語句中的子句也是SUBQUERY。
7)、DEPENDENT UNION:UNION 被依賴。
示例 2:
explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;輸出:
說明:from 子查詢 被優化了,所以未顯示。
示例 3:
explain select * from ( select * from actor where id = 1 union all select * from actor where id = 2 ) a輸出:
說明:derived2 表示 是第2條語句產生的派生表。
示例 4:
explain select (select name from actor where id = a.actor_id ) as name from (select * from film_actor where film_id =1 ) a輸出:
示例 5:
explain select * from film_actor where actor_id in ( select id from actor where id = 1 union all select id from actor where id = 2 )結果:
table 列
這一列表示 explain 的一行正在訪問哪個表。 當 from 子句中有子查詢時,table列是 格式,表示當前查詢依賴 id=N 的查詢,于
是先執行 id=N 的查詢。
partitions 列
如果是分區表,則表示是哪個分區。
type 列
這一列表示關聯類型或訪問類型,即MySQL決定如何查找表中的行,查找數據行記錄的大概范圍。
-
ALL:全表掃描
-
index:也是全表掃描。掃描表時按索引次序進行,而不是行(即掃描索引的全部記錄,然后再查找記錄行)。
它的主要優點是:避免了排序。最大缺點,按索引次序讀表有很大開銷。extra顯示“USING INDEX”表明使用覆蓋索引,不會再掃描數據表。
-
range:范圍掃描,一個有限制(部分數據)的索引掃描。范圍掃描通常出現在 in(), between ,> ,<, >= 等操作中。使用一個索引來檢索給定范圍 的行。
-
ref:也叫索引查找,返回所有匹配 某個單值的 行。相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前綴,索引要和某個值相比較,可能會找到多個符合條件的行。
-
eq_ref:一種索引查找,最多只返回一條記錄。primary key 或 unique key 索引的所有部分被連接使用 ,最多只會返回一條符合條件
的記錄。這可能是在 const 之外最好的聯接類型了,簡單的 select 查詢不會出現這種 type。
-
const,system:部分優化轉成常量。用于 primary key 或 unique key 的所有列與常數比較時,所以表最多有一
個匹配行,讀取1次,速度比較快。system是const的特例,表里只有一條元組匹配時為system 。
-
NULL:在優化階段就能返回值,例如 min,max。即通過數據庫記錄的統計數據進行查詢,不真正查詢表。
依次從最優到最差分別為:system > const > eq_ref > ref > range > index > ALL
一般來說,得保證查詢達到range級別,最好達到ref 。
示例 6:
explain select min(id ) from film ;輸出:
示例 7:
explain select count(name ) from actor ; -- name沒有在索引中 explain select count(id ) from actor ; -- id 在索引中,聚集索引。 explain select count(name ) from film ; -- name 在索引中,非聚集索引。輸出:
示例 8:
explain select * from actor where id > 1 ;結果:
示例 9:
explain select * from actor where id =1;結果:
示例 9:
explain select * from film_actor left join film on film_actor.film_id = film.id; explain select * from film where name = "film1";輸出:
possible_keys 列
這一列顯示查詢可能使用哪些索引來查找。
explain 時可能出現 possible_keys 有列,而 key 顯示 NULL 的情況,這種情況是因為表中數據 不多,mysql認為索引對此查詢幫助不大,選擇了全表查詢。
如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查 where 子句看是否可以創造一個適當的索引來提高查詢性能,然后用 explain 查看效果。
key 列
這一列顯示mysql實際采用哪個索引來優化對該表的訪問。 如果沒有使用索引,則該列是 NULL。如果想強制mysql使用或忽視possible_keys列中的索引, 在查詢中使用 force index、ignore index。
key_len 列
這一列顯示了mysql在索引里使用的字節數,通過這個值可以算出具體使用了索引中的哪些列。
ref 列
這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量), 字段名(例:film.id)
rows 列
這一列是mysql 估計 要讀取并檢測的行數,注意這個不是結果集里的行數。
Extra 列
這一列展示的是額外信息。常見的重要值如下:
- Using index:查詢的列被索引覆蓋,并且where篩選條件是索引的前導列,是性能高的表現。一般是使用了覆蓋索引(索引包含了所有查詢的字段)。對于innodb來說,如果是覆蓋索引性能會有不少提高。
- Using where:查詢的列未被索引覆蓋,where篩選條件非索引的前導列
- Using where Using index:查詢的列被索引覆蓋,并且where篩選條件是索引列之一但是不是索引的前導列,意味著無法直接通過索引查找來查詢到符合條件的數據
- NULL:查詢的列未被索引覆蓋,并且where篩選條件是索引的前導列,意味著用到了索引, 但是部分字段未被索引覆蓋,必須通過“回表”來實現,不是純粹地用到了索引,也不是完全沒用到索引。
- Using index condition:與Using where類似,查詢的列不完全被索引覆蓋,where條件中 是一個前導列的范圍;
- Using temporary:mysql需要創建一張臨時表來處理查詢。出現這種情況一般是要進行優化的, 首先是想到用索引來優化。
總結
以上是生活随笔為你收集整理的mysql explain实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最全的IDEA快捷键
- 下一篇: mysql树形结构查询_MySQL递归查