SQL優化之 - 必用命令explain

sql在進行查詢的時候首先,與MySQL建立連接,然后查詢緩存,緩存中存在,則直接返回,緩存中沒有,通過解析器對sql進行解析,然后通過查詢優化器對sql進行優化(包括重寫查詢、選擇合適的索引等等..),然后去存儲引擎中查詢結果。

而對sql性能影響非常關鍵的一步,就是查詢優化器對sql的優化,而"explain"就是去查詢優化器中查詢sql的執行計劃。

explain(翻譯:執行)

  • 執行計劃格式
explain +  具體sql

我們先來一個簡單地執行計劃:

explain select * from dept where id = 5

explain select * from dept where id in (select id from employee)
image.png
image.png

我們可以看到,一條執行計劃會展示12個相關的字段,下邊我們 一 一 了解一下這些字段的額含義:

  • id
含義:是一組數字,表示select子句或者是操作表的順序
規則:
1.id不相同的,id值越大越先執行
2.id值相同的從上到下順序執行
  • select_type
simple:簡單的select語句(不包括union操作或子查詢操作)
primary:查詢中最外層的select(如兩表做union或者存在子查詢的外層的表操作為primary,內層的操作為union)
union:union操作中,查詢中處于內層的select,即被union的select
subquery:子查詢中的select
derived:表示包含在 from 子句中的 select 查詢
union result:union的結果,此時id為null
  • table
    涉及到的表
  • type(重要)
    這列很重要,顯示了連接使用哪種類型,有無使用索引,
    常見的值從最好到最差如下:
    system > const > eq_ref > ref > range > index > all
    各值的描述如下:
1.system:表只有一行,MyISAM引擎所有。
2.const:常量連接,表最多只有一行匹配,通常用于主鍵或者唯一索引比較時,如:
explain select * from dept where id=5
3.eq_ref:表關聯查詢時,對于前表的每一行,后表只有一行與之匹配。
(1) join查詢
(2) 命中主鍵或者非空唯一索引
4.ref:只使用了索引的最左前綴或者使用的索引是非唯一索引、非主鍵索引
5.range:between,in,>等都是典型的范圍(range)查詢 如:explain select * from dept where id BETWEEN 5 and 8;
6.index:需要掃描索引列上的全部數據, 如:explain select id from dept
7.All:全表掃描 如:explain select * from dept 
  • possible_keys
    表示可能用到的索引
  • key
    表示最終用到的key
  • ref
    顯示索引的哪一列被使用了,有時候會是一個常量:表示哪些列或常量被用于查找索引列上的值
  • rows
    估算出結果集行數,表示MySQL根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數, 原則上 rows 越少越好。
  • filtered
    查詢結果的行數占上面rows的百分比
  • Extra(重要)
    這一列也很重要,主要展示額外的信息說明,能夠給出讓我們深入理解執行計劃進一步的細節信息
    常見的值及描述如下:
Using filesort:當order by 無法利用索引完成排序時,優化器不得不選擇合適的算法從內存或者磁盤進行排序
Using temporary:使用了臨時表
Using index:select后面的查詢字段在索引中就可以取到,無需再回表了,即所謂的覆蓋索引,這種查詢性能很好
Using index condition:mysql5.6之后引入了ICP(索引條件下推)
Using where:Mysql 服務器在存儲引擎檢索行后再進行過濾

優化原則

1. 讓主要查詢語句使用到合適的索引,type出現ALL(全表掃描)需格外注意,
同時建立合適的索引以減少possible_keys的數量

2. type最好能達到ref級別                                                           

3. Extra列出現Using temporary、Using filesort(文件排序)務必去除

優化思路

針對上面提到的幾點優化原則,提供如下的優化思路:
上述1,2點其實都可以通過優化索引來達到目的,而要想讓我們建的索引達到最優,則需要依據一個原則: 三星索引原則,簡單描述就是:
☆: where后條件匹配的索引列越多掃描的數據將越少,
比如組合索引(a,b,c),最好在where后面能同時用到索引上的a,b,c這三列
☆: 避免再次排序
簡單來說,就是排序字段盡量使用索引字段,因為索引默認是排好序的,使用索引字段排序可以避免再次排序
☆: 索引行包含查詢語句中所有的列,即覆蓋索引
基于這一點,我們應該少用select *來查詢,以增加覆蓋索引的可能性
如果你的索引能集齊上述三顆星,則說明你的索引是最優的索引!

基于第3點,
我們創建如下用戶表:

CREATE TABLE `t_user`  (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `group_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1240277101395107842 CHARACTER SET = utf8mb4 
COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

分組表:


CREATE TABLE `t_group`  (
  `id` bigint(20) NOT NULL,
  `group_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

并插入一些數據。
我們首先來看下Using filesort,出現Using filesort常見的有以下幾種情況:

  1. order by 的字段不在where條件中,比如:下面這條sql會出現Using filesort:
select * from t_user where group_id = 2 and age = 32 order by name;

但是下面這條sql不會:

select * from t_user where group_id = 2 and age = 32 order by group_id ;
  1. 組合索引跨列: 舉例: 給t_user表創建索引(name,age,group_id),
    則下面這條sql排序會出現Using filesort:
select * from t_user where name= '李A' order by group_id;

但是下面這條就不會:

select * from t_user where name = '李A' order by age;

因為第一條查詢order by跳過了age,直接使用了group_id;
刪除索引(name,age,group_id);

  1. 由于group by第一步默認進行了排序,所以當group by 的字段滿足上述條件是,也會出現
    Using filesort,可以在group by后面加上order by null取消排序。

最后,我們來看下Using temporary(使用了臨時表):
臨時表的出現對性能影響是很大的,主要會出現在以下情況中:

  1. 分組字段不在where條件后面,并且group by字段不是最終使用到的索引,原因有點類似于上面的Using filesort:
    比如:
    下面這條sql會出現Using temporary:
select * from t_user where group_id = 2 and name= '李A' group by age;

但是下面這條sql不會:

select * from t_user where name = '李A' and age = 21 group by age;

結論: where哪些字段,就group by 哪些字段.

  1. 表連接中,order by的列不是驅動表中的
    如下sql是會創建臨時表的:
explain select * from t_user t1 left join t_group t2 on t1.group_id = t2.id order by t2.id;

因為t1和t2連接的時候,t1是驅動表,但是排序使用了被驅動表t2中的字段。改為t1的字段排序就不會出現臨時表了,這里就不舉例了。
結論: 連接查詢的時候,排序字段使用驅動表的字段

  1. order by和group by的子句不一樣時
    如下Sql:
explain select * from t_user group by group_id order by `name`;

這種情況只能盡量使用同一個字段來分組和排序了,否則無法避免

  1. distinct查詢并且加上order by時
    如下sql:
explain select DISTINCT(`name`) from t_user order by age;

這種情況有時候無法避免,只能盡量將distinct的字段和order by的字段使用相同的索引。
還有會出現臨時表的情況有: from 中的子查詢、union,這里就不一一舉例了。

此文章參考:https://kuy8.com/sIFEp

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容