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