SQL優化 MySQL版 - 單表優化及細節詳講

單表優化及細節詳講

做者 : Stanley 羅昊html

轉載請註明出處和署名,謝謝!

注:本文章須要MySQL數據庫優化基礎或觀看前幾篇文章,傳送門:mysql

B樹索引詳講(初識SQL優化,認識索引):https://www.cnblogs.com/StanleyBlogs/p/10413349.htmlsql

B樹索引進階(索引分類、建立方式、刪除索引、查看索引、SQL性能問題):https://www.cnblogs.com/StanleyBlogs/p/10416865.html數據庫

SQL執行計劃於笛卡爾積(瞭解什麼是SQL執行計劃,優化原理):https://www.cnblogs.com/StanleyBlogs/p/10422202.html工具

Type詳講(理解優化級別):https://www.cnblogs.com/StanleyBlogs/p/10426385.htmlpost

Extra(理解最終優化概念):https://www.cnblogs.com/StanleyBlogs/p/10429969.html性能

優化準備

首先咱們須要有一個數據庫,bookdb,還要有一張數據表book,有如下字段,咱們接下來將用如下這張表來作優化實例;測試

單表優化

這次教程再也不使用可視化工具,由於效率太慢,我仍是比較喜歡命令行操做;優化

下面咱們須要編寫如下條件的SQL語句:spa

查詢authorid = 1而且 typeid爲2或3的bid再根據typeid排序

SQL語句:select bid from book where typeid in (2,3) And authorid = 1 order by typeid desc;

咱們執行這條SQL語句,而後在前面加上explatin查看sql執行計劃:

咱們能夠清楚的看到,查詢級別是ALL,而且Useing where回表查詢了而且後面還有一個Using filesort表示建立臨時表了,可見此條SQL語句是多麼的恐怖,效率極低

這個時候咱們就來給它加個索引吧,畢竟都知道,加索引能夠提升效率,那咱們就來分析一下以上這個sql語句;

首先該語句裏面有 bid typeid authorid這三個字段,那麼接下來我將給它們建立一個複合索引:

索引名我起名爲idx_bta表明它的順序 b 表明 bid t 表明 typeid a 就表明authorid;

加上索引後,咱們再執行一下,看看咱們這條sql語句有沒有被優化:

首先,咱們能夠看見,type級別被優化了一些,到了index了,也就是ALL的上一個級別,我在以前的文章也說過,最好優化到ref級別,可見咱們如今這條SQL仍是不夠優化,而且 咱們後面還有Using filesirt,可是出現了Using index,說明仍是優化了一些,可是遠遠不夠!

那麼爲何呢?我明明加了索引,它竟然還性能這麼差?

原來,咱們忽略了一點,就是SQL解析過程

我在前幾篇文章重點說過,編寫過程,解析過程是不同的:

編寫過程: 

select from join on where 條件 group by 分組 having過濾組 order by排序 limit限制查詢個數

解析過程:

from on join where group by having select order by limit 

以上就是mysql的解析過程,咱們發現,跟咱們編寫的過程徹底不一致!

也就是說,咱們儘管bid在前面,typeid跟authorid在後面,可是它實際執行的時候倒是先執行where(type、authorid),而不是select(bid);

可是咱們索引順序是怎麼建的?

是 b t a 的順序(bid typeid authorid),既然where我如今非要先讓bid先執行,很顯然不知足最佳左前綴,就是從左向右依次執行,我如今的索引並無知足,由於我如今卻讓最右邊的先執行了(bid)

因此,咱們須要改變一下索引的順序,既然先解析where,我就讓where後面的倆字段放在前面(typeid authorid),把select放在後面(bid);

根據SQL實際解析的順序,調整索引的順序;

在創建這個索引以前,咱們務必刪掉沒用的索引

刪掉後,咱們把索引的順序改變一下,以前是 b t a 如今我改爲 t a b(typeid authorid bid);

添加索引後,我而且查詢索引,發現建立成功了,咱們再運行一下試試,此次我改變了索引順序,順序按照解析順序排列,看看此次的效果如何:

咱們發現,type等級仍然是index,由於沒有建立臨時表了也就是額外的查詢,性能明顯提高了,可是咱們的type等級還是index,確實尚未達到咱們想要的ref標準,接下來咱們繼續優化;

咱們如今開始重點優化索引級別,很顯然,咱們的索引級別是index,距離ref還有點距離;

再次優化

system>const>eq_ref>ref>range>index>ALL

很明顯啊,咱們如今的這條sql纔到index級別,我以前說過,最好達到ref或range級別;

咱們來把以前的SQL拿過來:

 select bid from book where typeid in (2,3) And authorid = 1 order by typeid desc;

我如今將where條件後面這兩個字段換一個順序,爲啥換順序呢,看這個in

我以前講過範圍查詢,in是有可能致使索引失效的,從而轉爲無索引;

我如今思路是,若是in失效了或typeid失效了,那你authorid也就跟着一塊兒失效了,爲何呢?

咱們來看一下索引順序,咱們是先typeid 後 authorid,若是你typeid都沒了,那麼authorid也可能也受干擾了,因此我把它順序換換;

alter table book add index idx_atb(authorid,typeid,bid);

我如今讓它先authorid後typeid,那若是先a 後 t 那便是你 t 失效了,無所謂啊,我先a,a你也用了,這是個思路;

既然typeid會失效,那咱們改變一下where後面的順序吧,既然你可能會失效,就把它日後放,別影響別人

explain select bid from book where authorid = 1 And typeid in (2,3) order by typeid desc;

務必也把索引順序也更改一下!

alter table book add index idx_atb(authorid,typeid,bid);

咱們改變索引順序跟SQL語句where後面的順序後再執行:

咱們再查看type級別會發現已經達到了fef級別,而且也有Using index,可是還有Using where

由於我typeid雖然也有索引,可是我使用了in,就索引失效了就跟typeid沒有索引同樣,這樣就形成了又須要回原表查了,因此儘可能避免使用in;

小結:之因此這條SQL語句能達到了ref,是由於我知足了最佳左前綴,跟處理了索引失效的問題,既然你要失效,我就不要讓你影響後面的字段,我就把你日後排,儘管你失效了,你不影響前面的,因此我把SQL語句where後面的兩個字段換了位置;

索引須要逐步優化,要實時查詢sql執行計劃,採起逐步優化措施;

補充

剛剛在上方我把SQL語句字段where後面的字段調換了位置,而且索引也跟着調換了,其實通過測試,其實SQL語句無需調換,僅需調換索引位置便可:

今日感悟:

在你看不見的地方,總有你想不到的辛酸;

相關文章
相關標籤/搜索