記一次SQL調優
insert
優化
如果你在某一時刻有大量的insert
操作,一條一條插入是非常耗時的。insert
語句本身支援一次插入很多條記錄,插入記錄數上限受sql語句長度限制,一般一次插個幾千條是沒問題的。在我的 《如何手動實現Try Insert和Insert Or Update》 一文中對於各種情況都有具體的例子,這裡就不贅述了。
explain
語句結果分析
SQL本身是一種對機器來說抽象級別很高的語言,我們通過SQL告訴DBMS我們需要什麼,而沒有告訴它具體要怎麼做。DBMS會猜測性地以最優的方法去完成我們給的任務,但是它往往做得不太好,畢竟不同業務最優做法各不相同,目前我們還沒有辦法讓機器完全理解我們的業務。所以我們需要輔助機器,幫助它找到最好的查詢邏輯。通常的做法是新增合適的索引,讓所有的查詢都走索引。在MySQL中,在任何一個select
explain
,就可以知道MySQL對這條查詢的理解和實際執行邏輯。
下面來分析explain
語句返回的結果。explain
會展示查詢涉及到的每張表分析結果,裡面有很多引數,我們一般只需要關注以下幾個引數:
type
type描述表是怎麼
join
的,按從最好到最壞一共有以下幾個值:值 解釋 system 表只有一行,是一種特殊的 const
typeconst 表裡只有一行匹配的記錄, join
時可以認為是常量eq_ref 使用的索引為 primary key
或unique not null index
ref join
只使用最左字首匹配原則的普通索引fulltext 使用全文檢索索引 ref_or_null 與 ref
差不多,主要是多了NULL值的查詢index_merge 使用了MySQL的索引合併優化 unique_subquery 類似 eq_ref
,主要用於包含IN子查詢的查詢range 走索引的範圍查詢 index 索引樹被整個掃了,速度比掃表好一點 ALL 整個表被掃,非常糟糕的情況,一般要避免 一般做SQL優化,通常出現
index
和ALL
都是需要優化的。Extra
MySQL查詢的附件資訊,有時候代表著查詢的額外代價,出現
Using filesort
、Using temperary
都表示查詢速度不行。Using filesort
order by
子句不走索引,使用檔案排序,需要對order by
進行優化。Using temperary
表示查詢過程中建立了臨時表,通常發生在包含group by
和order by
的查詢中。
rows和filtered
rows
表示MySQL預估的查詢需要的行數,filtered
表示根據條件過濾之後的行所佔的百分比。值為100表示沒有行被過濾掉。所以rows
*filtered
查詢需要的總的行數。這個值自然是越小越好。
查詢優化實踐
查詢優化的策略就是加索引,primary key 和 unique key在根據具體業務定,我們做優化,一般都是新增普通索引。普通索引分為兩種,單個欄位的索引和多個欄位的聯合索引。聯合索引的應用場景相對窄一點,如果你要查的資料可以被聯合索引全部囊括,直接從索引拿資料,可以考慮使用聯合索引。讀多寫少重複值少雜湊分佈的欄位最適合建索引。你可以把你的程式使用到的所有SQL都列出來,一條一條explain
,沒有走索引的,就酌情給某個或某幾個欄位(join
裡的欄位、where
裡的欄位都是重點考慮物件)加上索引,直到所有的查詢走索引為止。這麼做以後,你的查詢type正常都可以到達比較好的情況,但是對於包含order by
子句的查詢,可能你的Extra資訊就不太理想了。Using filesort
和Using temperary
有時候陰魂不散,很難搞。這時候最佳的策略就是變著花樣選擇排序的欄位。比如你的表有一個自增主鍵,你可以考慮用它作為插入時間來做排序。MySQL本身在這方面的優化非常糟糕,需要耐心地多嘗試。
Reference
MySQL explain
MySQL ORDER BY優