改善SQL效能

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會比較快有以下兩點

  1. 如果連接id(key)帶有索引值,就可直接參照索引值,不需觀察Class_B資料表
  2. EXISTS與要找到一筆符合條件的列,就會停止搜尋,而IN則會全面搜尋一遍

2.避開排序

事實上DBMS非常頻繁地執行排序,因此使用者不用理會哪種運算正在執行排序。

  1. 善用集合運算字的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效能,但最重要一點是找出瓶頸,然後優先解決