編寫高效 SQL 語句的最佳實踐

iSQlServer發表於2010-11-30

 SQL 語言是一種強大而且靈活的語言,在使用 SQL 語言來執行某個關係查詢的時候,使用者可以寫出很多不同的 SQL 語句來獲取相同的結果。也就是說,語法 (syntactical) 不同的 SQL 語句,有可能在語義 (semantical) 上是完全相同的。但是儘管這些 SQL 語句最後都能返回同樣的查詢結果,它們在 DB2 中執行所需要的時間卻有可能差別很大。這是為什麼?

眾所周知,DB2 資料庫具有強大的功能,可以自動地把使用者輸入的 SQL 語句改寫為多個語義相同的形式並從中選取一個耗時最少的語句來執行。但是 DB2 並不能夠永遠對所有的 SQL 語句都成功的改寫來取得最優的執行方案。其中一個方面的原因就是資料庫應用程式的開發人員在寫 SQL 語句的時候有一些習慣性的“小問題”,而正是這些小問題帶來了 SQL 語句執行時效能上的大問題。正如平時所說“條條大路通羅馬”,但是並非所有通往羅馬的路都是坦途,我們應該找到那條最有效的道路。

編寫高效 SQL 語句的一些最佳實踐

這裡我們將介紹在編寫 SQL 語句時可能影響 DB2 查詢效能的一些常見問題,並給出相應的編寫高效 SQL 語句的最佳實踐(best-practices)。

避免不恰當的使用“SELECT *”

像“SELECT *”這樣的寫法在使用者使用中可能很常見,它表示把滿足查詢條件的每一條記錄(Row)的所有列都返回。但是有時候這種用法很可能導致資料庫查詢時候的效能問題。假定 Sale 是一個包括 25 個列(column)的表,那麼下面這條查詢語句就有可能在執行時效能較差,其中一部分原因就是在 SELECT 中使用了"*".

 SELECT *FROM Sales WHERE YEAR(Date) > 2004 AND Amount > 1000 

 

如果 SQL 語句使用了“SELECT *”,DB2 就需要把表的所有列都從外部儲存介質上(如磁帶或者硬碟)複製到 DB2 的記憶體中來進行處理並且返回給使用者,這顯然會增加 I/O 和 CPU 的開銷。而且如果這條 SQL 語句還包括了排序(Sort)操作(比如 ORDER BY),那麼對全部這些列進行排序也可能會影響到效能。而且當表定義的列越多,每個列定義的資料型別(Data type)長度越長,這對效能的影響就可能越明顯。除此之外,DB2 還有一種被稱為“Index-Only”的資料訪問方法,如果某個表上需要檢索的所有列都能在某個合適的索引(Index)上找到,DB2 就會使用“Index-Only”這種資料訪問方式。因為這種訪問方式僅需要對索引進行檢索而無需對錶本身進行讀取,所以是一種較快高速的訪問方式。但是如果使用者輸入的 SQL 語句中使用了“SELECT *”,就意味著需要訪問表上的所有列。而通常情況下並不存在一個合適的索引是定義在這個表所有的列之上的(尤其是對於定義了許多列的表),這就使得 DB2 無法使用“Index-Only”這種較快的資料訪問方式,而改用其他資料訪問方式,這也有可能導致查詢效能的問題。

所以除非真的需要讀取表中的所有列,否則基於提高查詢效能的考慮,在寫 SQL 語句的時候應該儘量避免使用“SELECT *”這樣的情況。這是一條很簡單卻常常被使用者忽略的最佳實踐。

下面來看一個具體的示例。需要說明的是,本文示例中用到的表,除特別說明外,均為 TPC-D 標準中定義的表,這樣有助於讀者更好的理解 SQL 語句本身。對於 TPC-D 標準的介紹,見文章最後的參考資源。

在這個例子中,我們比較 2 個不同的 SQL 語句在效能上的差別。2 個 SQL 的謂詞完全相同,並且這個謂詞有符合的索引可以使用。

 SQL 1:select * from lineitem where l_orderkey = ?  
 SQL 2:select l_suppkey, l_partkey from lineitem where l_orderkey = ? 

 

但是 SQL 1 使用了 select *,所以 DB2 在讀取索引之後,必須再去對錶中進行一次 Fetch 操作,讀取那些索引中不存在的列資料。而在實際業務需求中如果並不需要這些資料,這個 Fetch 操作就是多餘的而且會帶來效能問題。對比 SQL 2,它明確指出了在結果集中希望得到的列 l_suppkey, l_partkey,而這些列已經全部包含在索引中,所以資料庫採用了 Index-Only 的掃描方式,僅僅讀取了索引,不再需要對錶本身的 fetch 操作,從而使得效能得到了大幅提升。


圖 1. SQL 1 的訪問路徑圖
圖 1. SQL 1 的訪問路徑圖

 

 

圖 2. SQL 2 的訪問路徑圖
圖 2. SQL 2 的訪問路徑圖 

避免在本地謂詞的列上使用複雜表示式

所謂的本地謂詞(Local predicate)是與連線謂詞(Join predicate)相對應,它一般是指該謂詞當中只包含一個表上的一個列。

在上一節看到的例子當中,YEAR(Date) > 2004 和 Amount > 1000 都是兩個本地謂詞。然而在前一個謂詞 YEAR(Date) > 2004 中,它對 Date 這個列有一個函式 YEAR 的呼叫。在這種情況下,即使 Date 上存在一個索引,DB2 也無法使用這個索引來訪問資料。如果能夠在確保語義不變的前提下,適當改寫這個謂詞,避免在 Date 列上呼叫函式,那麼情況可能會有所不同。例如,這個謂詞可以改寫為如下的樣子:

 Date > ‘ 2004-12-31 ’

 

這樣的改寫首先確保了語義上的一致性,更重要的是,DB2 對於這樣的謂詞是可以通過索引來訪問資料,這樣查詢效能可能會比之前快很多。

這裡再給出一個類似的例子。對於 INTEGER(Sale)/100 = 900 這樣的謂詞,也可以將其改寫為 Sale BETWEEN 90000 AND 90099 來提高查詢效能。

通過上面兩個例子,可以得出一個對應的最佳實踐的理論公式。如果在本地謂詞中出現如下的形式:

 Function(Column_A)= ‘ constant ’

 

那麼儘可能的將其改寫為如下的形式會有助於查詢效能的提高:

 Column_A=Inverse_Function( ‘ constant ’ ) 

 

這裡 Column_A 是表上的某個列,constant 是常量,而 Function 與 Inverse_Function 是兩個互逆的函式。

這是在寫 SQL 語句時的另一個最佳實踐:儘量避免在本地謂詞中對於表的某個列使用複雜的表示式(函式呼叫或者數學運算等等)。

下面來看一個具體的示例:

 SQL 3:select l_quantity, l_comment from lineitem  where l_orderkey + 100 = 200  SQL 4:select l_quantity, l_comment from lineitem  where l_orderkey = 100 

 

圖 3. SQL 3 的訪問路徑圖
圖 3. SQL 3 的訪問路徑圖 

圖 4. SQL 4 的訪問路徑圖
圖 4. SQL 4 的訪問路徑圖 

這裡兩個 SQL 語句在語義上是完全相等的,只有謂詞在寫法上存在一些差異。SQL 3 的謂詞包含了一個 計算表示式 l_orderkey + 100 = 200,而 SQL 4 的謂詞是與之等價的簡單形式 l_orderkey = 100。但是它們的查詢訪問路徑可能會截然不同。對於 SQL 4,DB2 利用已有的索引,採用了較為高效的索引訪問方式(Index-scan);而 SQL 3 的謂詞存在計算表示式,DB2 必須先計算出 l_orderkey + 100 的值再進行匹配,這使得直接利用索引的索引訪問方式無法採用。這兩種不同的訪問路徑所帶來的效能也是大不一樣的,這一點對比圖中兩者的 Total Cost 就可以看出,謂詞中含有計算表示式 l_orderkey + 100 = 200 的 SQL 3 的 Total Cost 較高,效能不好。

避免用複雜表示式構建連線謂詞

所謂連線謂詞(Join predicate),一般是指該謂詞引用到了不同表上的多個列。比如在如下的 SQL 語句中:

 Select T1.C1 From T1, T2 Where T1.C1=T2.C2 And T1.C2=10 

 

T1.C1=T2.C2 就是一個典型的連線謂詞,這種寫法也是常見的連線謂詞的形式。對於這種常見的連線謂詞,DB2 可以考慮採用幾種不同的表連線方式(Join Method),常見的連線方法有巢狀迴圈連線(Nested-Loop-Join, NLJ),歸併排序連線(Merge-Scan-Join, MSJoin),雜湊連線(Hash-Join)等。DB2 優化器會根據實際情況選擇從中選取一個效能最佳的來將 T1 和 T2 連線起來。

但是有的 SQL 語句可能會是如下這個樣子:

 Select T1.C1 From T1, T2 Where T1.C1 * T1.C2 = T2.C2

 

在連線謂詞 T1.C1 * T1.C2 = T2.C2 中,“=”左邊不是一個列名,而是一個表示式,它涉及 T1 表上不同列之間的計算。對於這樣一個用複雜表示式構建的連線謂詞,DB2 只能用 Nested-Loop-Join 這種最基本的方式來建立 T1 和 T2 之間的連線,而不考慮用其他的連線方式,從而也就無法選擇最優的連線方式。所以這種在連線謂詞中使用複雜表示式的寫法不是一個好的習慣,在寫 SQL 語句時應該注意避免。

看下面這個示例:

 SQL 5: SELECT l_comment, o_comment FROM lineitem, order  WHERE l_orderkey = o_orderkey + 100  SQL 6: SELECT l_comment, o_comment FROM lineitem, order  WHERE l_orderkey = o_orderkey 

 

在這個例子中,SQL 5 中的連線謂詞中包含了一個計算表示式 l_orderkey = o_orderkey + 100,而 SQL 6 中的連線謂詞是簡單的等式 l_orderkey = o_orderkey。這樣不同的連線謂詞對 DB2 選擇連線方法時有重要的影響。在 SQL 5 中,連線謂詞中包含計算表示式,DB2 只能選用最基本的 Nested-Loop-Join 連線方法(參見圖 5)。對比 SQL 6,假設連線謂詞是 l_orderkey = o_orderkey 這樣簡潔的形式,DB2 就會採用 Merge-Scan-Join 的連線方式(見圖 6)。注意這裡 SQL5 與 SQL6 在語義上是不等價的,在這裡用這樣的示例是為了說明連線謂詞的寫法會導致連線方式的改變。如果想在滿足業務邏輯需求的情況下,同時保證連線謂詞的簡潔,也可以考慮增加一個新的列(例如 SQL 5 中,定義新的列 o_orderkey2,其值等於 o_orderkey + 100),直接構造連線謂詞(l_orderkey = o_orderkey2),從而最大程度的提高 SQL 語句的效能。


圖 5. SQL 5 的訪問路徑圖
圖 5. SQL 5 的訪問路徑圖

 

 

圖 6. SQL 6 的訪問路徑圖
圖 6. SQL 6 的訪問路徑圖 

避免連線謂詞中的資料型別不一致

在用連線謂詞連線不同的表的時候,還有一點需要注意。即使對於 T1.C1=T2.C1 這樣典型的連線謂詞,也應該確保 T1.C1 和 T2.C1 具有同樣的資料型別。

在某些情況下,連線謂詞中兩個列的資料型別定義的不一致會導致 DB2 放棄使用某些表連線方式。比如 Hash-Join 這種表連線方式對連線謂詞就有更多的限制條件,條件之一就是連線謂詞中的兩個列的資料型別必須完全一致,否則 Hash-Join 不能使用。例如,如果連線謂詞中的 T1.C1 是 FLOAT 型別,而 T2.C1 是 REAL 型別,那麼 DB2 不會使用 Hash-Join 來連線 T1 和 T2。此外,如果 T1.C1 的資料型別是 CHAR,GRAPHIC,DECIMAL 或者 DECFLOAT,那麼 T2.C1 除了需要是相同的資料型別外,它所定義的資料型別的長度也需要和 T1.C1 一致,比如都被定義為 CHAR(5),否則也不能使用 Hash-Join 來連線。

更多的表連線方式意味著 DB2 可以有更多的選擇來將表連線在一起,並從中選出最優的方案。如果連線謂詞中的資料型別不一致,而使得 DB2 不得不放棄某些特定的連線方式,這將有可能導致 SQL 在執行時效能不夠好。所以在不同的表之間建立連線關係時,應該避免連線謂詞中的資料型別不一致。

看下面這個示例:

 SQL 7: SELECT l_comment, o_comment FROM lineitem, order  WHERE l_orderkey = o_orderkey 

 

對於 SQL 1,DB2 優化器採用了歸併排序 (MSJoin) 的連線方法對兩個資料表進行了連線操作 ( 如圖 7 所示 ),注意根據 TPC-D 標準的定義,這裡連線謂詞 l_orderkey = o_orderkey 中的 2 個列的資料型別完全一致都為 integer 型別。如果改動其中一個列的資料型別為 double 型別,此時 DB2 就只能採用巢狀迴圈連線方法進行連線操作(如圖 8 所示),而對比之後就會發現,使用巢狀迴圈連線的 Total Cost 較高,這意味著效能較差。


圖 7. SQL 7 的訪問路徑圖
圖 7. SQL 7 的訪問路徑圖

 

 

圖 8. SQL 7 的訪問路徑圖(修改 o_orderkey 資料型別之後)
圖 8. SQL 7 的訪問路徑圖(修改 o_orderkey 資料型別之後) 

確保在連線謂詞中使用等號

典型的連線謂詞通常是形如 T1.C1=T2.C1 這樣的形式,注意到這裡是用“=”這個操作符將左右兩邊的列連線起來。理論上,也可以使用其他的操作符來構造連線謂詞,比如“”這樣的比較運算子。但是實際上基於效能的考慮,在連線謂詞中應該只使用“=”,儘量避免使用其他的比較運算子。

對於如下的 SQL 語句:

 Select T1.C2 From T1, T2 Where T1.C1 < T2.C1 

 

在連線謂詞 T1.C1 < T2.C1 中,使用了“

此外,對於這樣沒有使用“=”的連線謂詞,DB2 在計算這個謂詞的篩選率(selectivity)的時候,有可能計算的不夠準確,而如果同樣的連線謂詞改為用“=”連線,篩選率的計算就會準確很多。熟悉 DB2 的資料庫管理員和資料庫程式開發人員都會知道,篩選率的準確性對於 DB2 優化器非常重要。只有基於準確的篩選率,DB2 優化器才能從各種可能的訪問路徑中確定最優路徑。而篩選率不準確,就有可能帶來潛在的查詢效能問題。

基於上述兩點可以看出,“=”在構建連線謂詞時很重要。在不同的表之間建立連線關係時,應該儘可能的使用“=”來構建連線謂詞。

需要指出的是,在某些實際的應用場景當中,出於業務邏輯上的要求,出現 T1.C1 < T2.C1 這樣的連線謂詞可能是不可避免的。在這種情況下,基於效能優化的考慮,應該在 T1 和 T2 上都建立適當的索引,使得 T1.C1 < T2.C1 這個謂詞能夠使用索引。其中的原因在於,DB2 只能使用 Nested-Loop-Join 來建立 T1 和 T2 之間的連線,此時應該確保有合適使用的索引能夠讓 Nested-Loop-Join 採用 Index-Scan 這種資料訪問方法,從而儘可能提高效能。但是對於上面提到的第二個篩選率問題,即使新增索引也不能很好的解決這個問題。

看下面的示例,

 SQL 8: SELECT l_comment, o_comment FROM lineitem, order  WHERE l_oderkey >o_orderkey  SQL 9: SELECT l_comment, o_comment FROM lineitem, order  WHERE l_oderkey =o_orderkey 

 

在 SQL 8 中連線謂詞是通過大於號連線的,DB2 只能採用巢狀迴圈連線 (Nested-Loop-Join) 這種最基本的方式來建立兩個表之間的連線(如圖 9 所示)。在 SQL9 中連線謂詞中採用“=”連線,此時 DB2 優化器選用了歸併排序(MSJoin)的連線方式,它的 Total cost 比 SQL 8 的要低很多,具有較好的效能(如圖 10 所示)。注意這裡 SQL 8 與 SQL 9 在語義上是不等價的,在這裡用這樣的示例是為了說明連線謂詞中不使用等號的寫法會導致訪問路徑完全不同,從而影響查詢效能。


圖 9. SQL 8 的訪問路徑圖
圖 9. SQL 8 的訪問路徑圖

 

 

圖 10. SQL 9 的訪問路徑圖
圖 10. SQL 9 的訪問路徑圖 

確保主鍵與外來鍵之間的連線謂詞

表之間的主鍵外來鍵反映了表之間資料的依賴關係。如果一個 SQL 語句涉及兩個表之間的連線,而這兩個表存在主外來鍵關係,那麼通常情況下,該 SQL 語句中都應該有基於該主外來鍵關係的連線謂詞。在寫 SQL 語句的時候,也應該注意這一點,即根據主外來鍵關係確保 SQL 中存在對應的連線謂詞,否則的話,返回的查詢結果中可能會包括大量無實際意義的記錄,而返回這些記錄又會給資料庫執行帶來額外的開銷,造成效能問題。

來看一個簡單的例子,假設在表 T1 與 T2 之間存在主外來鍵的關係,其中 T1.C1 是主鍵,T2.C1 是外來鍵。如果有如下的 SQL 語句:

 SELECT T1.C2, T2.C2  FROM T1, T2  WHERE T1.C2 = 5  AND T2.C2 = ‘ IBM ’ AND T1.C3 = T2.C3 

 

注意在這個 SQL 當中,T1 與 T2 之間有一個連線謂詞 T1.C3 = T2.C3,但是卻缺少 T1.C1 = T2.C1 這樣的連線謂詞。而通過 T1 與 T2 之間的主外來鍵關係,可以合理推匯出在通常情況下,使用者想看到的結果中應該包括 T1.C1 = T2.C1 這樣的邏輯關係。因此可以將上面的 SQL 改寫為:

 SELECT T1.C2, T2.C2  FROM T1, T2  WHERE T1.C2 = 5  AND T2.C2 = ‘ IBM ’ AND T1.C3 = T2.C3  AND T1.C1 = T2.C1

 

通過新增這樣的連線謂詞,使得資料庫可以有更多的選擇來建立 T1 與 T2 直接的連線關係,並且避免了返回大量無意義的記錄,從而使得整體效能得以提高。但是需要注意的是,這樣的寫法改變了原先 SQL 的語義,從而改變了查詢結果,所以在使用的時候需要使用者來確認 T1.C1 = T2.C1 這樣的邏輯條件對於其業務應用來說是正確的。

看下面的示例:

 SQL10: SELECT l_comment, o_comment FROM lineitem, order  SQL11: SELECT l_comment, o_comment FROM lineitem, order  WHRE l_orderkey = o_orderkey

 

其中 SQL10 沒有包含 lineitem 和 order 表之間的主外來鍵關係 l_orderkey = o_orderkey,從業務邏輯分析的角度出發來看,這樣的寫法很可能是由於人為的疏忽漏掉了這個連線謂詞。從圖 11 中也可以看出,SQL 10 返回了一個很大的結果集(圖中 Cardinality 所示),可以合理推斷,其中包含了大量 l_orderkey ≠ o_orderkey 的無效資料,這些資料是業務邏輯並不想要的,而 DB2 為了取得這些無效資料卻要花費很高的代價。對比 SQL 11,具有 l_orderkey = o_orderkey 這樣的主外來鍵連線謂詞,更符合邏輯。同時從圖 12 也可以看出,它返回的結果集較小,所花費的成本(Total Cost)也小了很多,查詢效能優化很多。


圖 11. SQL 10 的訪問路徑圖
圖 11. SQL 10 的訪問路徑圖

 

 

圖 12. SQL 11 的訪問路徑圖
圖 12. SQL 11 的訪問路徑圖 

恰當安排 Group By 子句中列的順序

通常情況下,SQL 語句中的 GROUP BY 子句會導致資料庫不得不通過一個排序(SORT)操作來實現對資料的分組,而排序被認為是一個比較耗費 CPU 和記憶體的操作。實際上某些情況下,如果寫法得當,當中的排序操作是可以避免的。具體來說,在寫 GROUP BY 子句的時候,應該考慮到資料庫中已經存在的索引的情況。如果 GROUP BY 子句中所有的列恰好包括在某個索引的鍵(Key column)的範圍之內而且是處於開始的位置,那麼在寫 GROUP BY 子句的時候,就應該按照該索引上鍵的先後順序來寫 GROUP BY 子句。

比如說有如下的 SQL 語句:

 SELECT C2, C3, C1, AVG(C4)  FROM T1  GROUP BY C2, C3, C1

 

一般情況下,GROUP BY C2, C3, C1這樣的寫法都會導致資料庫的一個排序操作。但假定表 T1 上已經存在一個索引 IX1(C1, C2, C3, C4), 這裡注意到 GROUP BY 子句中引用到的列(C2,C3,C1)正好是索引 IX1 中的前三個鍵,那麼就可以通過改變 GROUP BY 子句中列的順序的辦法來避免這個排序操作。

可以把 SQL 語句改寫為如下所示:

 SELECT C1, C2, C3, AVG(C4)  FROM T1  GROUP BY C1, C2, C3

 

通過這樣改變 GROUP BY 子句中列的順序使其與索引 IX1 中的鍵順序一致,資料庫就可以利用 IX1 來訪問其已經排序的鍵值並直接返回進行下一步操作,從而避免額外的排序操作,從而帶來查詢效能上的提高。

需要指出的是,通過這樣改寫 GROUP BY 子句來避免排序,可能會導致最終返回結果的順序不一致。在實際的業務邏輯當中,需要使用者來確認是否其關注返回結果的順序性。

下面來看一個具體的示例:

 SQL 12:SELECT AVG(o_shippriority) FROM order  GROUP BY o_custkey , o_orderkey, o_orderdate  SQL 13:SELECT AVG(o_shippriority) FROM order  GROUP BY o_orderkey, o_orderdate, o_custkey 

 

這裡 2 個 SQL 唯一的差別就在於 GROUP BY 子句中列的順序不同。根據 TPC-D 標準定義,order 表上存在一個索引 PXO@OKODCKSPOP (O_ORDERKEY,O_ORDERDATE,O_CUSTKEY,O_SHIPPRIORITY,O_ORDERPRIORITY)。

由於 SQL 12 中的 GROUP BY 子句的列順序與索引 PXO@OKODCKSPOP 的鍵順序不一致,DB2 無法直接利用這個索引,所以 DB2 需要基於這 3 個列做一次排序(Sort),然後進行分組合並,排序的結果還需要通過臨時檔案(Wkfile)來儲存,如圖 13 所示。如果調整 GROUP BY 子句中的列順序如 SQL 13 所示,使其與索引 PXO@OKODCKSPOP 的鍵順序一致,DB2 通過這個索引返回的結果就已經是有序的,這樣就省去了排序操作(如圖 14 所示)。對比兩者的訪問路徑圖可以看出來,SQL 13 所花費的成本(Total Cost)會少很多,效能上有較大的提高。


圖 13. SQL 12 的訪問路徑圖
圖 13. SQL 12 的訪問路徑圖

 

 

圖 14. SQL 13 的訪問路徑圖
圖 14. SQL 13 的訪問路徑圖 

配合使用 OPTIMIZE FOR N ROWS 與 FETCH FIRST N ROWS ONLY

在 DB2 的 SQL 語法中,FETCH FIRST n ROWS ONLY 表示只取回結果集當中的前 n 條記錄。這在實際的業務邏輯中會經常用到,比如查詢考試成績在前三名的學生,或者是薪水最高的五位公司員工。而 OPTIMZE FOR n ROWS 這個子句可能並不被一般使用者所熟悉,它的作用是告訴 DB2 的優化器採用儘可能快的方式來返回結果集中的前 n 條記錄,但是注意最終結果集中的所有記錄都會被返回,這是它與 FETCH FIRST n ROWS ONLY 的不同。

通常情況下,取得結果集中的全部記錄(比如 1000000 條)與取出其中的前 n 條記錄(比如第 1 條記錄)相比,最優化的方法是不一樣的。比如對於後者而言,通過索引來訪問可能是最快的,而這種訪問對於前者卻未必是最佳的訪問方式。也就是說,如果想要只取回結果集當中的前 n 條記錄,應該使得 DB2 優化器知道這一點,從而選取最優的訪問方式。

所以如果 SQL 語句中帶有 FETCH FIRST n ROWS ONLY 這個子句,那麼應該同時加上 OPTIMZE FOR n ROWS 子句來配合使用。比如對於如下的 SQL 語句:

 SELECT e.name FROM employee e, department d  WHERE e.workdept = d.deptno  FETCH FIRST 10 ROWS ONLY

 

可以加上 OPTIMZE FOR n ROWS 子句變為如下的形式:

 SELECT e.name FROM employee e, department d  WHERE e.workdept = d.deptno  FETCH FIRST 10 ROWS ONLY  OPTIMIZE FOR 10 ROWS 

 

這樣一來,DB2 優化器就會盡量採用最優化的方式來儘快返回前 10 條結果,比如避免採用一個臨時表來儲存中間結果,從而達到查詢效能上的提升。

總結

本文介紹了在編寫 SQL 語句時幾種可能影響 DB2 查詢效能的常見問題,並給出相應的編寫高效 SQL 語句的最佳實踐,它們對於資料庫程式開發人員在 DB2 上進行 SQL 查詢效能調優時非常重要。如果你的 SQL 語句寫的高效簡潔,你就可以有效的避免在 DB2 查詢時可能出現的效能問題,從而減少總的成本並提高客戶業務的投資回報。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16436858/viewspace-680674/,如需轉載,請註明出處,否則將追究法律責任。

相關文章