一次浴火重生的MySQL優化(EXPLAIN命令詳解)

        一直對SQL優化的技能心存無限的嚮往,以前面試的時候有不少面試官都會來一句,你會優化嗎?我說我不太會,這時可能不少人就會有點兒說法了,好比會說不要使用通配符*去檢索表、給經常使用的列創建索引、還有建立表的時候注意選擇更優的數據類型去存儲數據等等,我只能說那些都是常識,做爲開發人員是必需要知道的。但真正的優化並非使用那些簡單的手法去完成實現的,要想知道一條SQL語句執行效率低的緣由,咱們能夠藉助MySQL的一大神器---"EXPLAIN命令",EXPLAIN命令是查詢性能優化不可缺乏的一部分,本文在結合實例的同時會總結explain命令的使用及相關參數的說明。面試

       首先說說我此次浴火重生的優化初衷吧,上個月在公司完成的統計模塊中,其中就有幾條SQL語句執行的速度稍微有點慢,內心一直留了一道坎。直到昨天晚上在家看了一篇文章,是關於MySQL優化的對EXPLAIN命令的詳解,因此今天一到公司就想着把以前那些SQL語句的病趕忙給看看,雖然,我沒有達到那種秒查的效果,可是優化的效果仍是有明顯的提高。性能優化

業務場景:

分區統計XXX省每個月上傳數據的企業數量,何爲企業是不是未上傳數據,即專門存放上傳數據的數據表中沒有記錄的爲未上傳數據的企業,若是有那麼表明已經上傳數據。

下面是我以前寫的SQL語句(未優化前的),它執行的時間是2.318sec,而且使用EXPLAIN命令進行分析:性能

首先說說EXPLAIN命令查詢後打印的數據列它們各個列表明的意思:學習

  一、id :該列的值是用來順序標識整個查詢中SELELCT 語句的執行順序,在嵌套查詢中id越大的語句越先執行,該值可能爲NULL。我的建議,能夠在分析一條很長的SQL語句時能夠依照它的值來按順序進行切割分析優化。優化

  二、select_type :表示當前select查詢的類型,該列可能出現的值還有以下狀況;spa

   三、table :對應行正在訪問哪個表,表名或者別名(注意:MySQL對待這些表和普通表同樣,可是這些「臨時表」是沒有任何索引的);翻譯

  • 關聯優化器會爲查詢選擇關聯順序,左側深度優先blog

  • 當from中有子查詢的時候,表名是derivedN的形式,N指向子查詢,也就是explain結果中的下一列索引

  • 當有union result的時候,表名是union 1,2等的形式,1,2表示參與union的query id開發

  四、type :該列的值表明的含義是訪問數據表的檢索類型,也是最爲重要的優化指標之一,它的好壞狀況依次是  system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL ,通常來講,得保證查詢至少達到range級別,最好能達到ref級別,下面是各個值表明的意思。我的建議:能夠在分析一條很長的SQL語句時,儘可能讓每一個拆分的檢索子句都到理想的優化級別;

   五、possible_keys :顯示查詢使用了哪些索引,表示該索引能夠進行高效地查找,可是列出來的索引對於後續優化過程多是沒有用的,也就是說該索引在查找的時候未必真正的使用上。

  六、key :該列表示在檢索時實際決定使用的鍵(索引)。若是沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

  七、key_len :該列顯示MySQL決定使用的鍵長度。若是鍵是NULL,則長度爲NULL。使用的索引的長度。在不損失精確性的狀況下,長度越短越好 。

  八、ref :該列表示使用哪一個列或常數與key一塊兒從表中選擇行,我的翻譯:就是當前檢索中的語句與哪一個表中的列聯合查找數據的。

  九、rows :該列顯示MySQL認爲它執行查詢時必須檢查的行數。注意這是一個預估值。我的建議:該值若是比整表總記錄數越低,則越好。

  十、Extra :該列的值是EXPLAIN輸出中另一個很重要的列,該列顯示MySQL在查詢過程當中的一些詳細信息,MySQL查詢優化器執行查詢的過程當中對查詢計劃的重要補充信息。咱們一般根據該列的值來判斷SQL語句是否須要優化;

 

根據上面的知識分析:

       我經過MySQL EXPLAIN分析的思路是這樣的:一般首先要根據id的值肯定當前檢索語句是什麼時候執行的,注意分析的時候按順序分析,其次在根據type列的值來判斷當前檢索語句是否須要優化,最後看決定性的一點就是根據Extra的值,上面表格中也說了,若是看到Using temporary通常就須要優化了。

       由於我上面的那條語句是一個子查詢,因此我首先根據id的值找到最早執行的檢索語句,也就是嵌套在最內層的那條等值查詢語句,它分別使用等值條件去鏈接企業表和上傳數據表篩選出符合條件的數據,可是使用EXPLAIN命令分析得出,這條檢索語句並非真正的高效,在掃描org表的時候進行了全表數據鏈接而不是有條件的去刷選鏈接,並且在等值鏈接的時候並未真正使用主鍵索引去等值鏈接,再回過頭來仔細想一想咱們的業務,就是拿着info表中的數據去org表中進行匹配,固然全表掃描info是避免不了的,可是org表不必定所有都掃描啊,因此我試着用左鏈接替代以前的等值鏈接,果真效果達到了,info表進行了全表數據匹配去鏈接org表中的數據,而且在匹配的時候org表的主鍵索引也真正使用到了,級別達到了eq_ref,至於info表的ALL級別,毋庸置疑業務須要必須就是要去掃描整表的;最後看到最外層的檢索語句也未必是高效的,它關聯的地區表也進行了全表數據匹配,可是我要的查詢結果是根據子查詢結果來得出的,確定不比子查詢結果的數據多,因此我將子查詢結果做爲左表去匹配地區表中的數據,果真,由ALL級別變成range級別,檢查的行數也由3646減小到了15,通過分析優化執行速度提高1秒多,優化級別基本達到理想的狀態,因爲本人能力有限,只能作到這步:

以上都是本人通過實踐得出,並不是亂寫,若是有地方總結不到位,但願各位留言補正,共同窗習,共同進步,一直在優化的路上。

相關文章
相關標籤/搜索