常用的SQL語句優化技巧

說到系統性能優化涉及的內容就比較多了,從業務需求到系統架構設計再到實現過程中的中間件、存儲層等等的設計,這些都是需要充分規劃的。

涉及存儲層,從數據庫選型,數據庫設計,索引規劃、查詢方式,任一環節都可能引入性能風險。

本文主要從數據庫SQL查詢優化的角度優化查詢性能,數據庫選型是MySQL。

SQL查詢優化

應儘量避免在 WHERE 子句中使用 != 或 <> 操作符,否則將導致引擎放棄使用索引而進行全表掃描。MySQL只有對以下操作符才使用索引:,>=,BETWEEN,IN,以及某些方式的LIKE('a%'),如下。

WHERE 子句中使用 LIKE進行模糊查詢時,在關鍵詞前加%或者前後都加%號都無法使用索引,而進行全表掃描,如下。

應儘量避免在 WHERE 子句中對字段進行 NULL 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,創建表時NULL是默認值,但大多數時候應該使用NOT NULL,或者使用一個默認值,如 0 作為默認值,如下。

應儘量避免在 WHERE 子句中使用 OR 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描。使用 OR 的字句可以分解成多個查詢,並且通過UNION 連接多個查詢。他們的速度只同是否使用索引有關,如果查詢需要用到聯合索引,用UNION ALL執行的效率更高,如下。

應儘量避免在 WHERE 子句中使用 IN 和 NOT IN ,否則將導致全表掃描,對於連續的數值,能用 BETWEEN AND 儘量避免使用 IN。一般,用 EXISTS 代替 IN 。若需要使用 IN,在 IN 後面值的列表中,按照值的分佈數量降序排列,減少判斷的次數,如下。

使用BETWEEN AND 替換 IN

使用EXISTS 替代IN,用NOT EXISTS 替代 NOT IN

使用LEFT JOIN 替換 IN

如上,我們使用瞭如下方式優化了IN 和 NOT IN:

使用between 替換 in使用exists替代in、用not exists替代 not in使用left join 替換 in

應儘量避免在 WHERE 子句中對 “=” 左邊的字段進行函數、算術運算及其他表達式運算,可以將表達式運算移至“=”右邊,否則將導致引擎放棄使用索引而進行全表掃描,如下。

如果在 WHERE 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時。它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項,可以改為強制查詢使用索引,如下。

避免使用 select * from table,用具體的字段列表代替

* ,避免返回用不到的任何字段,如下。

在使用索引字段作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引(遵循最左前綴原則),否則該索引將不會被使用,並且應儘可能的讓字段順序與索引順序相一致。

最後,現代計算機科學的鼻祖 Donald Knuth曾提到“過早的優化是萬惡之源……”。我想有性能風險意識 不等同於 需要過早或者過度優化。

"