Extra
作者 : Stanley 羅昊
【轉載請注明出處和署名,謝謝!】
注:此文章必須有一定的Mysql基礎,或觀看執行計划入門篇傳送門:
https://www.cnblogs.com/StanleyBlogs/p/10416865.html
終於總結到哦SQK執行計划的最后一個知識點了:
Extra
Extra有以下幾個值,它們都非常重要,它們表示你的SQL語句的最終性能,以下將介紹它的幾種值,每個值都代表你的SQL語句的缺陷:
1.Using filesort
主要出現在 order by 排序、復合索引跨列;
order by 排序
出現原因:查詢a表,卻根據b表排序,例如:
select * From test01 where a = '3' order by b;
如果避免此情況出現,就根據什么字段查,就根據什么字段進行排序。如:
select test01 where a = '3' order by a;
執行結果:
如果沒出現那就表明你這個SQL沒毛病很顯然上圖我沒出現👆,如果出現出現這個👇,說明你當前SQL語句需要“額外”的一次排序,我們理解起來就是,需要額外的一次查找;
假設我我們現在創建一張表test02,里面有 a1 a2 a3字段,然后分別給這三列字段添加索引;
這里我們就故意觸發一下:
select * From test01 where a = '1' order by b;執行結果如下:
”
講解:因為官方解釋說,你需要先查詢再排序,假設你要根據b來排序,這個時候你不需要查,但是數據庫會自動的幫你查一下后再去排序,如果你自己在它排序之前已經查過了,那就不需要再去排序了,性能自然就高了,從頭到尾僅需一次查詢即可,如果你根據a查詢卻再讓跟b查詢,那必然需要查兩次,性能自然不高了;
所以先查詢,再排序就非常符合情理,性能自然高;
小結:對於單索引,如果排序和查找是同一個字段,則不會出現using filesort;如果排序和查詢不是同一個字段,那就會出現using filesort;
避免策略:你where那些字段,就order by那些字段~
復合索引跨列
不能跨列,舉例說明:
為了防止上面a b c單值索引的干擾,我們全部刪掉,建一個復合索引:
altet table test01 add a_b_c_index (a,b,c);
顯示所有索引:show index from 表名
執行結果:
首先a b c 這三個字段我都加了索引,然后我執行以下語句:
explain select * From test01 where a = 1 order by c;
很顯然,我跨列了,因為a b c 你中間跨了一個b,在復合索引下,必須要從左一次向右走,不得從中間往后,也不能跨列,否則就會出現Usein filesort;
我現在符合規范使用復合索引:
這樣就沒有出現Usein filesort,因為我沒有跨列;
避免策略:where 和 order by 按照復合索引的順序使用,不要跨列或無序使用
2.Useing temporary
主要出現在:group by分組中
它同樣也是性能損耗較大,用到了臨時表,如果在執行的時候出現了Useing temporary,它就不單單的在查你條件中的表,而又多出來了一張表,多了這張表,你的性能就必然損耗了;
其實跟上面那個Usein filesort有點相似:
select * From test01 where a in (1,2,3) group by a;
我根據a查詢,我又根據a分組,這樣就不會出現Useing temporary,這里我也不放圖了;
如果我非要讓他Useing temporary出現也不難,就把sql語句改成:
select * From test01 where a in (1,2,3) group by c;
我根據a查詢,卻根據c進行分組,這里Useing temporary必然會出現;
道理很簡單:我查詢a,這個時候數據已經查出來了,我這時進行分組,就在你原查詢出來的數據上進行操作即可,但是如果你把a查出來的東西你不用,非要讓b進行分組,這個時候因為數據庫不知道b是誰,所以需要把b再查一遍出來放到臨時表進行排序;
避免Useing temporary策略:查詢那些列,就根據那些列進行分組 group by;
3.Using index
如果出現useing index,就表明這條sql性能提升了,看到它應該很高興;
這個詞兒(using index)翻譯過來應該是索引覆蓋,那么為什么性能就提升了呢?
原因在於:此次查詢,不讀取源文件,只從索引文件中獲取數據(不需要回表查詢);
什么是回表查詢?
講解:假設我建立一張表,這張表里面有id name age,我們假設根據age作為一個索引,比如說我現在寫一條語句:
select age From student where age = .....;
如果我這樣查詢,我們這個sql語句里面用到了age,但是age是我們定義好的索引,但是剛好我現在也只查age,這個時候它就不需要查原表,只需要查索引表!
這個就被稱之為不需要回表查詢;
我們現在只查詢索引表,不查詢其他表那肯定就快了,因為:
我假設原表占了100M,但是索引表才占了1M,因為索引必定是一小部分,我們在1M里面查age,肯定比在100M里面查age要快許多;
如果我們只查age,age剛好也在索引里面,這個我就不需要在原表里面去查了,就稱之為不需要回表查詢 ,這種情況就會出現一Using index;
總結:只要使用到的列全部都在索引中,就是索引覆蓋 using index;
舉例:
這個時候我們表中有一個復合索引,a b c均為索引列:
現在我們編寫一條SQL語句:
原因很簡單,我需要查詢的列分別是 a b 但是a b這兩個列都在索引中,所以造成了索引覆蓋,結果就成了Using index;
4.Using where
需要回表查,在上面我講了Using index,是不需要回表查,至於什么是回表,我在上面寫的非常清楚!
既然需要回表,那就說明我們接下來我想要的數據既在原表中,也在索引中,這個時候就不得不導致需要回表查;
舉例:
假設 一張表中 age 是索引列,但是查詢語句 select age,name from 表名 where age = ...;
這條SQL語句很顯然,age在索引里面,但是name 不在索引里,這種情況就必須回原表,並且會顯示Using where;
SQL語句:EXPLAIN SELECT a,d FROM test01 where a = '';
執行結果:
a是索引列,b不是所以就必須回表查,就導致結果為Using where;
今日感悟:
智者:“為什么想走絕路?”;
年輕人:“我得不到別人的承認,沒有人欣賞並且重用我”
智者:“請你把我剛才仍在地上的那粒沙子撿起來”
年輕人:“這根本不可能”
智者:“那你能不能幫我把這里珍珠撿起來呢?”
年輕人:“當然可以”
智者:“你應該明白,現在你自己還不是一顆珍珠,所以你不能苛求別人立即認同你,如果要別人認同你,並且重用你,你就想辦法把自己變成那顆被我仍在地上的珍珠吧”