SQL的效能微調永遠是DB工程師一直面對的課題。本篇將介紹五點提升SQL效能的方法,希望對讀者有幫助
1.若子查詢為參數,使用EXISTS代替IN
IN述詞很方便,但如果是以子查詢為參數,就建議用EXISTS。因為EXISTS通常能與IN述詞傳回相同的結果,但是建立子查詢卻快得多
例子
1.使用IN
SELECT * FROM Class_A WHERE id IN (SELECT id FROM CLASS_B);
2.使用EXISTS
SELECT * FROM CLASS_A A WHERE EXISTS
(SELECT * FROM Class_B B WHERE A.id=B.id);
EXISTS會比較快有以下兩點
- 如果連接id(key)帶有索引值,就可直接參照索引值,不需觀察Class_B資料表
- EXISTS與要找到一筆符合條件的列,就會停止搜尋,而IN則會全面搜尋一遍
2.避開排序
事實上DBMS非常頻繁地執行排序,因此使用者不用理會哪種運算正在執行排序。
- 善用集合運算字的ALL選項
例如UNION,如果不用在乎重複的資料或是事先知道不會有重複資料,可利用UNION ALL代替UNION,避免執行排序
例子
1.
SELECT * FROM CLASS_A
UNION
SELECT * FROM CLASS_B
2.
SELECT * FROM CLASS_A
UNION ALL
SELECT * FROM CLASS_B
- 以EXISTS代替DISTINCT
DISTINCT會排除重複資料。若是為了統整兩張資料表連結結果,建議可使用EXISTS代替DISTINCT,避免執行排序。
例子
1.
SELECT DISTINCT I.item_no FROM Items I INNER JOIN SalesHistory SH ON I.item_no = SH.item_no;
2.
SELECT item_no FROM Items I
WHERE EXISTS
(SELECT * FROM SalesHistory SH WHERE I.item_no=SH.item_no);
3.(MAX/MIN)使用索引值
MAX與MIN這兩種極值函數,使用時,都會進行排序,但如果參數的欄位已有索引值,就只需要掃描該索引值,不需搜尋整張表格
4.寫在WHERE陳述句的條件不寫在HAVING陳述句
例子
1.
SELECT sale_date, SUM(quantity) FROM SalesHistory
GROUP BY sale_date
HAVING sale_date = ‘2010-10-2’;
2.
SELECT sale_date, SUM(quantity) FROM SalesHistory
WHERE sale_date= ‘2010-10-2’ GROUP BY sale_date
已上例子,例子二(WHERE)的效能較佳,有兩個原因。第一是在正常情況下,WHERE陳述句可使用索引值。第二是GROUP BY陳述句執行的彙整會進行排序與雜湊的運算,所以先減少列數,才能減輕排序時的負擔。HAVING陳述句是對彙整後的試圖設定條件,但彙整後的試圖無法連原始資料表的索引值一併繼承
5.減少中介資料表
中介資料表的問題在需要大量記憶體,也很難使用資料表的索引(尤其是經過彙整後)。所以盡可能減少中介資料表可說是提升效能的關鍵點。
善用HAVING陳述句
SELECT * FROM(SELECT sale_date, MAX(quantity) AS max_qty FROM SalesHistroy
GROUP BY sale_date)TMP WHERE max_qty >= 10;
不過要對彙整的結果設定條件,是不需要建立多餘的中介資料表的,只要使用下列HAVING陳述句即可
SELECT sale_date, MAX(quantity) FROM SalesHistory
GROUP BY sale_date HAVING MAX(quantity) >= 10
HAVING陳述句會一邊執行,一邊進行彙整,所以會比建立中介資料表之後才執行WHERE陳述句更有效率,而且程式碼也比較簡潔
相信已上五點可要效提升SQL效能,但最重要一點是找出瓶頸,然後優先解決。