經過 「IBM DB2 for Linux, UNIX, and Windows 最佳實踐」專題,得到最經常使用的 DB2 9 產品配置實踐指南,並使用這些知識提升 DB2 數據服務器的價值。 數據庫
這些最佳實踐文章給出了最優化方法的建議,使您能使用 DB2 知足關鍵的業務數據處理需求。每篇最佳實踐文章都爲最經常使用的 DB2 產品配置提供了實踐指南。經過應用這些建議,您能夠提升 DB2 數據服務器的價值,而且可以始終把握 IBM 在 DB2 方面的技術方向。 編程
本文描述了在 DB2 數據庫性能方面最小化 SQL 語句的影響的最佳實踐。有幾種將影響減到最小的方法: 緩存
本文包括最佳實踐對適用於、通常的工做負載、數據倉庫工做負載和 SAP 工做負載,包括特定 SAP 商業智能(BI)應用程序。 性能優化
這裏有不少方法來處理應用程序編寫後特定的查詢性能問題。可是,本文專一於良好的基礎編寫和調優練習,這能更普遍的提升 DB2 數據庫性能。 服務器
若是你遵循了本文討論的建議後仍然碰到性能低下的問題,這也有不少技術可讓你理解爲何會性能低下。「性能調優和問題診斷最佳實踐」 最佳實踐文章描述了不少技術來定位性能問題和進行系統配置來防止它們。「物理數據庫設計最佳實踐」最佳實踐文章中描述瞭如何使用 DB2 數據庫系統功能,想多位集羣(MDC),物化查詢表(MQTs)和 DB2 Design Advisor 來達到優化查詢性能的目的。後面的最佳實踐文章將描述分析特定查詢性能問題的技術。 數據結構
對於提升 XQuery 性能的建議,參見「使用 DB2 pureXML 管理 XML 數據的最佳實踐」。 數據庫設計
回頁首 函數
查詢性能不能只考慮某一次的問題,而應該貫穿於應用程序開發的整個生命週期,在設計、開發、生產各個階段中都要考慮它。
SQL 是一個很是靈活的語言,也就是說有不少途徑一樣能夠得到正確的結果。這種靈活性也意味着利用 DB2 優化器具備優點,一些查詢會優於其餘的查詢。
在查詢運行的過程當中,DB2 優化器會爲每一個 SQL 語句選擇一個查詢計劃。優化器模擬不一樣的訪問計劃的運行成本,並選擇其中一個成本最低的訪問計劃。若是一個查詢包括不少複雜的搜索條件,DB2 優化器在某些狀況下能夠重寫謂詞,不過在某些一些狀況下卻不能。
對於一些比較複雜的查詢,一個 SQL 語句的準備或編譯的時間可能會比較長,尤爲是 BI 應用程序中使用的 SQL 語句。你能夠經過調整設計和你的數據庫配置來幫助縮短語句編輯時間。這包括選擇正確的優化級別並正確設置其餘註冊變量。
優化器也須要精確輸入以得到精確的查詢計劃。這意味着你須要收集精確的統計信息,並潛在的使用高級統計功能,好比統計視圖和列組統計信息。
你也可使用 DB2 工具(尤爲是 DB2 explain 工具)來調優查詢。 DB2 編譯器能夠抓取動態或靜態語句關於訪問計劃和環境的信息。利用抓取的信息來理解單個語句的運行,因此你能夠調整它們以及你的數據庫管理器配置來提升性能。
SQL 是很強大的語言,它容許你指定語法不一樣而語義相同的關係型描述。不過,一些語義相同的變化比起其餘的更容易優化。雖然 DB2 優化器有很強的查詢重寫能力,但也並不老是能夠把一個 SQL 語句重寫成最優的形式。某些 SQL 結構也可能會限制優化器對訪問計劃考慮。下面的章節描述了須要避免的某些 SQL 結構,並對如何替換或避免它們提出了建議。
在搜索條件中避免複雜的描述,這樣的描述阻止了優化器使用編目統計信息來評估一個精確的選擇。這個描述也可能會限制選擇能夠應用這些謂詞的訪問計劃。在優化的查詢語句的重寫階段,優化器能夠重寫一批描述以容許優化器評估一個精確的選擇;不過它不能處理全部可能性。
在描述中使用鏈接謂詞把鏈接方法限制爲了嵌套循環。另外,對基數的評估可能不許確。下面是一些鏈接描述的例子:
WHERE SALES.PRICE * SALES.DISCOUNT = TRANS.FINAL_PRICE WHERE UPPER(CUST.LASTNAME) = TRANS.NAME |
使用相反的描述來替代應用中的一個在本地謂詞上有太多列的描述。考慮下面的例子:
XPRESSN(C) = 'constant' INTEGER(TRANS_DATE)/100 = 200802 |
你可把它們語句重寫爲:
C = INVERSEXPRESSN('constant') TRANS_DATE BETWEEN 20080201 AND 20080229 |
應用多列的描述將妨礙索引開始和結束鍵的使用,從而致使不許確的可選評估,並須要在查詢運行時花費額外的時間來處理。這些描述一樣會阻止對查詢的重寫優化,好比在列相等時的識別、使用常量來替換各列而且對只有一行返回的狀況進行識別。在這以後的進一步的優化也可能會被阻止,所以會失去更多的優化機會。考慮下面的查詢:
SELECT LASTNAME, CUST_ID, CUST_CODE FROM CUST WHERE (CUST_ID * 100) + INT(CUST_CODE) = 123456 ORDER BY 1,2,3 |
你也能夠用下面的語句:
SELECT LASTNAME, CUST_ID, CUST_CODE FROM CUST WHERE CUST_ID = 1234 AND CUST_CODE = '56' ORDER BY 1,2,3 |
若是在 CUST_ID 上有一個惟一索引,重寫的查詢版本讓查詢優化器注意到最多一行記錄將被返回。這避免了引入一個沒有必要的排序操做。這也讓 CUST_ID 和 CUST_CODE 列被 1234 和‘ 56 ’替代,從而避免了從數據頁或索引頁複製數據。最終,使得在 CUST_ID 上的謂詞應用成一個索引開始或結束鍵。
當一個描述在謂詞中時,它可能不是總這麼明顯。這種狀況常常發生在涉及視圖的查詢中,尤爲當視圖列是經過描述定義的時候。好比,考慮下面視圖定義和查詢:
CREATE VIEW CUST_V AS (SELECT LASTNAME, (CUST_ID * 100) + INT(CUST_CODE) AS CUST_KEY FROM CUST) SELECT LASTNAME FROM CUST_V WHERE CUST_KEY = 123456 |
查詢優化器把查詢和視圖定義合併了,產生下面的查詢:
這是前面例子中有問題的謂詞。你能夠經過使用 explain 功能顯示優化後的 SQL 語句來觀察視圖合併的結果。
若是相反的功能很難表達,考慮使用一個生成列。例如,若是你想找到一個知足 LASTNAME IN ('Woo', 'woo', 'WOO', 'WOo', and so on) 描述標準的姓氏,你能夠建立一個生成列 UCASE(LASTNAME) = 'WOO' ,以下 :
CREATE TABLE CUSTOMER (LASTNAME VARCHAR(100), U_LASTNAME VARCHAR(100) GENERATED ALWAYS AS (UCASE(LASTNAME))) CREATE INDEX CUST_U_LASTNAME ON CUSTOMER(U_LASTNAME) |
在某些狀況下,數據類型不匹配將妨礙使用哈希鏈接。哈希鏈接在鏈接謂詞上比其餘鏈接方法要多一些約束。特別是鏈接列的數據類型必須徹底相同。例如,若是一個鏈接列是 FLOAT 另一個是 REAL,哈希鏈接將不支持。另外,若是鏈接列數據類型是 CHAR、GRAPHIC、DECIMAL 或 DECFLOAT 則長度必須同樣。
在謂詞中不要使用 no-op 描述來更改優化器評估
一個「 no-op 」 coalesce() 謂詞以「 COALESCE(X, X) = X 」會引入一個評估錯誤到使用它的全部查詢的計劃中。如今 DB2 查詢編譯器沒有能力不去選則那個謂詞並肯定是否全部的行具體知足它。做爲結果,這個謂詞減小了對來自於部分查詢計劃的評估的行數。這個更小的行估計一般爲後面的查詢計劃減小了行數和評估成本,而有時選擇不一樣計劃的結果是由於不一樣候選計劃之間的相關評估條件改變了。
爲何這個什麼都不作的謂詞有時候卻會提升查詢性能?增長謂詞「 no-op 」 coalesce() 引入了一個錯誤掩蓋了一些東西,要否則就是阻止了性能優化。
一些性能加強工具作了什麼是一個強力測試:工具一再引入謂詞到一個查詢的不一樣位置,操做不一樣的列,經過引入一個錯誤來嘗試找到一種狀況,這個錯誤出如今哪裏影響了一個更好的查詢計劃。這也是一個真正的查詢語句開發人員在一個查詢中手動。編寫「 no-op 」謂詞。一般,開發人員會獲得一些對數據的瞭解來指導這個謂詞的放置。
使用這個方法來提升查詢性能是一個短時間的解決方案,它並無定位根本緣由並且會有如下影響:
鏈接謂詞使用比較操做,除了相等其餘都應該避免。由於不相等鏈接方法就會限制爲嵌套循環。並且,優化器或許不能爲鏈接謂詞計算一個精確的可選評估。然而不等鏈接謂詞不能永遠規避。當它們是必須的時候,確保一個謂詞索引存在於任何一個表中,由於鏈接謂詞將應用嵌套內部鏈接。
不等鏈接謂詞的一個簡單例子是,爲了精確反映維度數據在不一樣的時間點的狀態,一個星型模式中的維度數據必須版本化。這經常做爲一個‘慢慢改變的維度’來被參考。一類慢慢改變的維度包括每一個維度行的有效的開始和結束日期。爲了鏈接維度的主鍵,一個在事實表和維度表之間的鏈接須要檢查和事實表相關的數據,包括維度的開始和結束日期。這經常做爲一個‘第 6 類慢慢改變的維度’被參考。範圍鏈接回到事實表經過一些實際事務日期以進一步限定維度版本,成本會很高。例如:
SELECT ... FROM PRODUCT P, SALES F WHERE P.PROD_KEY = F.PROD_KEY AND F.SALE_DATE BETWEEN P.START_DATE AND P.END_DATE |
在這個狀況下,須要確保有一個索引在(F.PROD_KEY, F.SALE_DATE)列上
能夠考慮建立一個統計視圖來幫助優化器計算一個更好的可選評估。例如
CREATE STATISTICAL VIEW V_PROD_FACT AS SELECT P.* FROM PRODUCT P, SALES F WHERE P.PROD_KEY=F.PROD_KEY and F.SALE_DATE BETWEEN P.START_DATE AND P.END_DATE ALTER VIEW V_PROD_FACT ENABLE QUERY OPTIMIZATION RUNSTATS ON TABLE DB2USER.V_PROD_FACT WITH DISTRIBUTION |
指定星型模式鏈接,好比索引 ANDing 星型鏈接,而且若是在查詢塊中有任何不等鏈接謂詞,集中鏈接不被考慮。(參見「若是你使用星型模式鏈接,確保你的查詢和必須匹配在 12 頁中的標準」)
避免使用在同一個 subselect 中運行多個 DISTINCT 集合的查詢,它的運行成本很是高。考慮下面的例子:
SELECT SUM(DISTINCT REBATE), AVG(DISTINCT DISCOUNT) FROM DAILY_SALES GROUP BY PROD_KEY; |
爲了判斷 DISTINCT REBATE 值和 DISTINCT COUNT 值,來自 PROD_KEY 表的輸入流須要進行兩次排序。這個查詢語句的查詢計劃就像這樣 :
優化器重寫了最初的查詢語句,分紅兩個單獨的集合,每一個指定 DISTINCT 關鍵字,而後把多個集合用 UNION 關鍵字鏈接起來。內部重寫的語句是:
SELECT Q8.MAXC0, (Q8.MAXC1 / Q8.MAXC2) FROM (SELECT MAX(Q7.C0) AS MAXC0, MAX(Q7.C1) AS MAXC1, MAX(Q7.C2) AS MAXC2 FROM (SELECT SUM(DISTINCT Q2.REBATE) as C0 , cast(NULL as integer) AS C1, 0 AS C2, Q2.PROD_KEY FROM (SELECT Q1.PROD_KEY, Q1.REBATE FROM DB2USER.DAILY_SALES AS Q1) AS Q2 GROUP BY Q2.PROD_KEY UNION ALL SELECT cast (NULL as integer) AS C0, SUM(DISTINCT Q5.DISCOUNT) AS C1, COUNT(DISTINCT Q5.DISCOUNT) AS C2, Q5.PROD_KEY FROM (SELECT Q4.PROD_KEY, Q4.DISCOUNT FROM DB2USER.DAILY_SALES AS Q4) AS Q5 GROUP BY Q5.PROD_KEY) AS Q7 GROUP BY Q7.PROD_KEY) AS Q8 |
若是你不能避免多個 DISTINCT 集合的話,就考慮使用帶 ENHANCED_MUTIPLE_DISTINCT 選項的 DB2_EXTENDED_OPTIMIZATION 註冊表變量。 這個選項將使到多個 DISTICT 集合的輸入流被讀取一次而後被 UNION 的每個分支重複使用。這個選項能夠在數據庫分區的處理器比率較低的時(例如,比率小於或等於 1)提升這類查詢的性能。這個設置應該對沒有對稱的多處理器的 DPF(Database Partitioning Feature)環境(SMPs)頗有用。這個優化擴展不能在全部環境中提升查詢性能。應該進行測試來判斷單個查詢性能的提升。
某些查詢的語義須要外鏈接(無論左、右或全鏈接)。然而,若是查詢語義不須要一個外鏈接並被用於處理不一致數據,那麼最好是處理不一致數據的根本緣由。例如,在一個數據集市中有一個星型模式,事實表可能包含事務數據,不過由於數據不一致的問題,形成與父維度行的一些維度不匹配。這是可能發生的,由於抽取、轉換和裝載(ETL)過程出於某些緣由不與商業鍵不兼容。在這種狀況下,事實表的行與維度左鏈接能夠確保它們即便在沒有父表的狀況下獲得返回。例如:
SELECT ... FROM DAILY_SALES F LEFT OUTER JOIN CUSTOMER C ON F.CUST_KEY = C.CUST_KEY LEFT OUTER JOIN STORE S ON F.STORE_KEY = S.STORE_KEY WHERE C.CUST_NAME = 'SMITH' |
左外鏈接會阻止一些優化,也包括使用指定的星型模式鏈接訪問方法。然而,在某些狀況下左外鏈接能夠自動被查詢優化器重寫成一個內部鏈接。在這個例子中,在 CUSTOMER 和 DAILY_SALES 之間的左外鏈接能夠被轉換成一個內部鏈接,由於 C.CUST_NAME= ’ SMITH ’謂詞將排除這一列中全部 NULL 值的行,使得一個左外鏈接語義變得沒有必要。因此因爲外鏈接的出現致使那些優化損失可能並不會對全部查詢產生負面影響。然而,注意到這些限制並避免外鏈接很是重要,除非它們是絕對必須的。
把 FETCH FIRST N ROWS ONLY 子句和 OPTIMIZE FOR N ROWS 子句放在一塊兒使用
OPTIMIZE FOR N ROWS 子句代表對於優化器應用程序打算只獲取 N 行,不過查詢將返回完整的結果集。 FETCH FIRST N ROWS ONLY 子句顯示查詢只需返回 N 行。
DB2 數據服務器不會在爲外部子查詢指定了 FETCH FIRST N ROWS ONLY 而自動假設 OPTIMIZE FOR N ROWS 。嘗試與 FETCH FIRST N ROWS ONLY 一塊兒指定 OPTIMIZE FOR N ROWS 來鼓勵查詢計劃直接從引用的表返回行,而不執行一個緩衝操做,好比插入一個臨時表、排序或插入一個哈希鏈接的哈希表。
應用程序指定 OPTIMIZE FOR N ROWS 來鼓勵查詢計劃避免緩衝操做,也不獲取整個結果集,它們可能致使性能低下。這是由於快速返回前 N 行的查詢計劃可能不是對於獲取整個結果集的查詢計劃。
優化器爲星型模式考慮兩個特殊的鏈接方法,叫作一個星型鏈接或集中鏈接,它們能夠明顯的提升性能。若是查詢必須知足如下標準。
一個查詢塊表現一個左外部連接或右外部鏈接,能夠只涉及兩個表,因此不符合一個星型模式的鏈接
不須要爲優化器能發現一個星型模式鏈接而顯示的聲明參考完整性。
避免多餘的謂詞,尤爲是當他們發生在不一樣的表的時候。在某些狀況下,優化器並不能判斷多餘的謂詞。這可能致使基數被低估。
例如,在 SAP BI 應用程序中雪花模式和實施表以及維度表被做爲一個查詢優化數據結構被用到。在一些狀況下會有多餘的時間特徵列(對於月的「 SID_0CALMONTH 」或對於年的 "SID_0FISCPER")定義在事實表和維度表中。
SAP BI OLAP 處理器在維度和事實表的時間特徵列上會產生多餘的謂詞。
這些多餘的謂詞可能產生很長的運行時間。
下面提供了一個例子,在一個 SAP BI 查詢中有兩個多餘的謂詞被定義在 WHERE 條件裏。相同的位謂詞定義在時間維度(DT)和事實(F)表。
AND ( "DT"."SID_0CALMONTH" = 199605 AND "F". "SID_0CALMONTH" = 199605 OR "DT"."SID_0CALMONTH" = 199705 AND "F". "SID_0CALMONTH" = 199705 ) AND NOT ( "DT"."SID_0CALMONTH" = 199803 AND "F". "SID_0CALMONTH" = 199803 ) |
DB2 優化器沒有注意到相同的謂詞,並對它們分別處理。這致使低估了謂詞、生成不是最優的訪問計劃以及更長的查詢運行時間。
處於這個緣由多餘的謂詞從 DB2 數據庫具體平臺軟件層面去掉了。
以上謂詞轉換成下面這一個。只有事實表「 SID_0CALMONTH 」列上的謂詞被保留:
AND ( "F". "SID_0CALMONTH" = 199605 OR "F". "SID_0CALMONTH" = 199705 ) AND NOT ( "F". "SID_0CALMONTH" = 199803 ) |
應用 SAP 957070 和 1144883 備忘錄來去掉多餘的謂詞。
有不少數據庫設計和配置選項能夠影響查詢性能。對數據庫設計的更多建議參考「 Planning your Physical Database Design 」最佳實踐文章。
考慮定義的惟一性,檢查並參考一致性約束。這些約束提供了語義信息,容許 DB2 優化器重寫查詢來評估鏈接,經過鏈接來下降聚合和 FETCH FIRST N ROWS,去掉沒必要要的 DISTINCT 選項被和一些其它的優化。當應用程序能夠保證它本身的關係時,信息約束也能夠被用來檢查並參考一致性約束。相同的優化也是能夠的。當更新(插入或刪除)行的時候,來自數據庫管理器的強制約束可能致使很高的系統開銷,尤爲在更新不少有一致性約束的行的時候。若是一個應用程序在更新一行以前已經驗證的信息,這樣使用信息約束比起正常的約束更有效
例如,考慮 2 個表 DAILY_SALES 和 CUSTOMER 。在 CUSTOMER 表中的每一行都有一個惟一的客戶鍵值(CUST_KEY)。 DAILY_SALES 包含一個 CUST_KEY 列而且每一行都引用一個 CUSTOMER 表中的客戶鍵。能夠建立一個參考一致性約束來防止在 CUSTOMER 和 DAILY_SALES 之間發生 1:N 的關係。若是應用程序要強制約束這個關係,能夠建立一個信息化的約束。那麼下面的查詢避免了在 CUSTOMER 和 DAILY_SALES 之間進行鏈接,由於沒有從 CUSTOMER 獲取任何列,並且來自於 DAILY_SALES 的每一行均可以在 CUSTOMER 裏面找到與之匹配的行,因此查詢優化器將自動刪除鏈接
SELECT AMT_SOLD, SALE PRICE, PROD_DESC FROM DAILY_SALES, PRODUCT, CUSTOMER WHERE DAILY_SALES.PROD_KEY = PRODUCT.PRODKEY AND DAILY_SALES.CUST_KEY = CUSTOMER.CUST_KEY |
應用程序必須執行信息約束,不然查詢可能返回不正確的結果。在上面的例子中,若是行存在於 DAILY_SALES 中,在 CUSTOMER 表中卻找不到相應的客戶鍵,那麼上面的查詢返回的行可能不正確。
在一個在線事務處理(OLTP)環境的中輸入變量有較好的語句準備時間是關鍵,在這樣的環境中語句每每比較簡單並且查詢計劃選擇也很簡單。使用不一樣的輸入變量屢次運行相同的語句能夠複用在動態語句高速緩存中編譯了的訪問片斷,避免了因爲隨時更改輸入值而形成昂貴的 SQL 語句編譯開銷。
然而,輸入變量對複雜的查詢負載也會形成問題,它們的查詢計劃選擇很是複雜,所以優化器須要更多的信息來作出好的決定。並且,語句編譯時間一般是總運行時間中的一個很小組成部分。由於 BI 查詢一般不會重複,因此並無從動態語句高速緩存上獲得好處。
若是在一個複雜查詢工做負載中須要使用輸入變量,請考慮使用 REOPT(ALWAYS) BIND 選項。當輸入變量值是已知的,REOPT BIND 選項從 PREPARE 到 OPEN 或執行過程當中推遲了語句編譯。變量值被傳遞到 SQL 編譯器中,這樣優化器可使用這些便利來計算一個更精確的選擇評估。 REOPT(ALWAYS) 表示全部執行語句都應該被預編譯。 REOPT(ALWAYS) 也能夠被用於涉及特殊寄存器的複雜查詢,好比 "WHERE TRANS_DATE = CURRENT DATE - 30 DAYS" 。若是輸入變量對 OLTP 工做負載形成較差的訪問計劃選擇,而且 REOPT(ALWAYS) 選項由於語句編譯形成過多的開銷,那麼考慮對挑選過的查詢使用 REOPT(ONCE) 。 REOPT(ONCE) 推遲語句的編譯直到首個數據變量被綁定。使用這個首個輸入變量值編譯並優化 SQL 語句。後續使用不一樣的值來運行的語句將重用基於第一個輸入編譯的查詢片斷。這是一個好方法 , 若是首個輸入變量表明瞭後續的輸入值,而且在輸入值未知的狀況下比起優化器使用不一樣的值進行評估,它提供個了一個更好的查詢訪問計劃 .
有不少方法來指定 REOPT:
rebind nullid.SQLC2G13 reopt always;
db2 bind db2clipk.bnd collection NULLIDR1; db2 bind db2clipk.bnd collection NULLIDRA; |
你可也能使用優化配置來爲靜態語句和動態語句設置 REOPT,以下面例子顯示的:
<STMTPROFILE ID="REOPT example "> <STMTKEY> <![CDATA[select acct_no from customer where name = ? ]]> </STMTKEY> <OPTGUIDELINES> <REOPT VALUE='ALWAYS'/> </OPTGUIDELINES> </STMTPROFILE> |
設置優化級別能夠得到顯式指定優化技術的好處,尤爲出於下面的緣由:
大多數語句能夠經過使用第 5 級優化獲得充分的優化和合理的資源,這也是默認的查詢優化級別。在一個給定的優化級別,查詢編譯時間和資源消耗是主要受查詢複雜度的影響,尤爲是鏈接以及子查詢的數目。不過,編譯時間和資源的使用一樣受到執行優化的影響。
查詢優化級別 1,2,3,5 和 7 適用於通常用途。只有你須要進一步減小查詢優化時間並且在你知道 SQL 語句很是簡單的狀況下才考慮級別 0 。
Tip:要分析一個運行很長時間的查詢,對查詢運行 db2batch 來找出花了多少時間在編譯上在運行上花費了多少時間。若是編譯須要更多的時間,下降優化級別。若是執行須要更多的時間那麼就考慮更高的優化級別
當你選擇了一個優化級別,考慮下面的通常準則:
在線事務處理(OLTP)事務是這種類型訪問的很好例子
優化級別 3 及其以上使用動態編程鏈接枚舉算法。這個算法考慮更多的可選計劃,而且可能招致比 0,1,和 2 更多的編譯時間,尤爲在表的數目增長後。
複雜查詢須要不一樣數量的優化來選擇最佳訪問計劃。對有下面特徵的查詢,請考慮使用更高的優化級別:
決策支持查詢或月底報告查詢對於數據庫是一個很常見的複雜查詢的很好例子,對於這類查詢優化級別至少應該使用默認值。
使用更高的查詢優化級別的 SQL 語句是由查詢生成器產生的。不少查詢生成器建立效率低下的查詢。寫得很拙劣的查詢,包括那些有查詢生成器產生的查詢,須要額外的優化以選擇一個好的訪問計劃。使用查詢優化級別 2 和更高的級別能夠提升那些 SQL 查詢。
對於 SAP 應用程序,老是使用優化級別 5 。這個優化級別啓用了不少爲 SAP 優化過的 DB2 功能,好比設置 DB2_REDUCED_OPTIMIZATION 註冊表變量。
DB2 數據服務器能夠經過在動態語句高速緩存中保存訪問片斷和語句文原本避免重複預編譯一個前面運行過的動態 SQL 語句。對這個語句的一個後續 PREPARE 請求將嘗試在動態語句高速緩存中查找訪問片斷來避免編譯。然而,只要謂詞在字面上有一點不一樣,這個語句高速緩存中的片斷就不一致。例如,下面兩個語句就在動態語句高速緩存中被看做不一樣的語句。
SELECT AGE FROM EMPLOYEE WHERE EMP_ID = 26790 SELECT AGE FROM EMPLOYEE WHERE EMP_ID = 77543 |
若是它們運行得太頻繁,相關 SQL 語句的編譯甚至會形成額外的系統 CPU 負擔。在「 Monitoring and Tuning the System 」最佳實踐文章中描述了 如何檢測這性能問題。若是你的系統遇到這類性能問題,應該考慮把應用程序改爲使用參數標記來把謂詞的值傳遞給 DB2 編譯器,而不要顯式的在 SQL 語句中包含它。不過,對於複雜的查詢若是使用參數標記那麼獲得的訪問計劃可能不是最優的。更多信息請參見「在複雜查詢中使用 REOPT 綁定選項和輸入變量」。
設置 DB2_REDUCED_OPTIMIZATION 註冊表變量
若是對你的應用程序設置的優化級別不能充分的減小編譯時間,那麼就嘗試設置 DB2_REDUCED_OPTIMIZATION 註冊變量。這個註冊變量在優化器查找空間上比設置優化級別提供了更多控制。這個註冊變量讓你能夠請求在指定的優化級別中減小優化功能或者嚴格使用優化功能。若是你減小了使用優化技術的數目,你一樣減小了時間和優化過程當中使用的資源。
注意:雖然優化時間和資源使用可能會減小,這也增長了產生的查詢計劃不是最優的風險。
首先,嘗試設置註冊表變量爲 YES 。若是優化級別是 5(默認值)或更低,優化器將不會使用某些須要花費大量準備時間和資源的優化技術,可是一般也不會產生更好的查詢計劃。若是優化級別是 5,優化器會減小或取消一些額外的技術,這可能進一步減小優化時間和使用的資源,不過一樣進一步增長了獲得的查詢計劃不是最優的風險。對於低於 5 的優化級別,它們的一些技術可能在任何狀況下都無效。
若是設置 YES 沒能充分縮短編譯時間,能夠嘗試設置這個註冊變量爲一個數字。效果是和 YES 同樣,對於在級別 5 上的動態準備查詢優化有後續的附加行爲。若是在任何查詢塊中鏈接的總數目超過了這個設置,那麼優化器就切換到一個貪婪鏈接枚舉算法而不是取消額外的優化技術。這樣的效果是查詢將在一個相似優化級別 2 的級別上被優化。
對 SAP 應用程序設置 DB2_WORKLOAD 註冊變量
對於 SAP 應用程序,老是會爲 SAP 設 DB2_WORKLOAD 註冊變量。這會觸發一批其餘的對 SAP 應用程序有特殊好處的 DB2 註冊表變量設置。下面是在這些便利中和 DB2 優化器相關的註冊變量設置
DB2_REDUCED_OPTIMIZATION 的設置是專門針對 SAP 工做負載的。不要在其餘應用程序下使用除非是 DB2 技術支持推薦的。
即便在指定了 REOPT(ONCE) 的狀況下,DB2_MINIMIZE_LIST_PREFETCH=YES 和 DB2_INLIST_TO_NLJOIN=YES 將依然保持活動。
精確的數據庫統計信息是查詢優化的關鍵。在全部對查詢性能來講很是關鍵的表上有規律的運行 RUNSTATS 。若是一個應用程序直接查詢這些表而且有大量的動態編目更新好比 DDL 語句,你可能也但願蒐集系統編目表的信息。能夠啓用自動蒐集統計信息功能來容許 DB2 數據服務器自動運行 RUNSTATS 。能夠啓用實時收集統計信息,經過馬上收集這些信息來讓 DB2 數據服務器在優化查詢以前能提供更及時的統計信息。
若是手動運行 RUNSTATS 來收集統計信息,你應該至少使用下面的選項。
RUNSTATS ON TABLE DB2USER.DAILY_SALES WITH DISTRIBUTION AND SAMPLED DETAILED INDEXES ALL |
分發統計信息可讓優化器知道是否有數據傾斜。當使用特定索引訪問表時,詳細的索引統計信息提供更多的 I/O 需求細節來預取數據頁。然而對大表收集詳細的索引統計信息會消耗不少的 CPU 和內存。 SAMPLED 選項提供了詳細索引統計信息和相同的精確性,卻只須要一小部分 CPU 和內存。當並無對一個表提供一個統計配置文件時,這些默認值一樣會被自動收集統計信息使用。
爲了提升查詢性能,考慮收集更多更高級的統計信息,好比列組的統計信息,LIKE 統計信息或建立統計信息視圖。
若是你的查詢不止一個鏈接謂詞來鏈接兩個表,在選擇一個執行計劃來運行查詢以前 DB2 優化器將計算如何選擇每一個謂詞。
例如,考慮以供廠商,他用有不少顏色的原料生產產品,彈性和品質。產品最後頁是和原料同樣的顏色。這個廠商執行了如下查詢:
SELECT PRODUCT.NAME, RAWMATERIAL.QUALITY FROM PRODUCT, RAWMATERIAL WHERE PRODUCT.COLOR = RAWMATERIAL.COLOR AND PRODUCT.ELASTICITY = RAWMATERIAL.ELASTICITY |
這個查詢返回了全部產品的名字和原材料品質。在這裏有兩個鏈接謂詞:
PRODUCT.COLOR = RAWMATERIAL.COLOR PRODUCT.ELASTICITY = RAWMATERIAL.ELASTICITY |
優化器會假定這兩個謂詞是獨立的,也就是說全部彈性對顏色的變化沒有關係。而後經過創建每一個表關於彈性等級數和不一樣的顏色數目的編目信息評估謂詞的總的可選組合,並基於這個評估。例如,比起合併鏈接它可能更傾向於選擇一個嵌套循環鏈接,反之亦然。
然而,這兩個謂詞可能並不獨立。例如比較高的彈性材料可能只有幾種顏色,並且彈性差的材料也可能不一樣於彈性好的材料只有剩下的其餘顏色。而後組合這些謂詞的選擇消除一些行,因此查詢將返回更多的行。沒有這些信息,優化器也許不會選擇最佳的計劃。
爲了在 PRODUCT.COLOR 和 PRODUCT.ELASTICITY 上收集列組統計信息 , 運行下面 RUNSTATS 命令:
RUNSTATS ON TABLE product ON COLUMNS ((color, elasticity)) |
優化器使用這些統計信息來檢測相關性,並動態調整相關的謂詞選項組合,所以獲得對鏈接的尺度和開銷更精確的評估。
當一個查詢須要數據以一個具體的方式(使用 GROUP BY 或 DISTINCT 關鍵字)編組時列組統計信息也會很是有用,由於優化器須要計算明確分組的數目。
考慮下面查詢:
SELECT DEPTNO, YEARS, AVG(SALARY) FROM EMPLOYEE GROUP BY DEPTNO, MGR, YEAR_HIRED |
沒有任何索引或列組統計信息,優化器評估分組的數目(也包括在這種狀況下返回的行數目)是 DEPTNO、MGR 和 YEAR_HIRED 的不一樣值的結果。這個評估假設分組鍵列是獨立的。然而,若是每一個管理員管理一個肯定的部門,這個假設就多是錯誤的。一樣,不大可能每一個部門每一年都僱用新員工。所以,不一樣 DEPTNO、MGR 和 YEAR_HIRED 值得結果多是對具體組的數目太高評估。
在 DEPTNO、MGR 和 YEAR_HIRED 上收集的列組統計信息將爲上面的查詢提供給優化器和有肯定數目的分組:
RUNSTATS ON TABLE EMPLOYEE ON COLUMNS ((DEPTNO, MGR, YEAR_HIRED)) |
爲了 JOIN 謂詞關係,優化器也管理簡單等價謂詞,好比
DEPTNO = 」 Sales 」 AND MGR = 「 John 」 |
在上面的 EMPLOYEE 表,在 DEPTNO 謂詞上極可能與在 YEAR 上的謂詞毫無關係。然而在 DEPTNO 和 MGR 上的謂詞卻確定相關,由於每一個單獨的部門可能常常在一段時間受到同一個經理的管理。優化器使用列的統計信息來判斷不一樣之的組合數目並對這兩列的關係調整選擇或計數評估。
若是你在模式結尾以外的任何位置對指定的 LIKE 謂詞使用 % 通配符,你都應該蒐集關於子元素結構的基本信息。
以及向通配符 LIKE 謂詞(例如,SELECT .... FROM DOCUMENTS WHERE KEYWORDS LIKE '%simulation%'),這列以及查詢必須知足某些標準來從子元素統計信息中獲利。
表列應該包括由空格分開的子域或者子元素。例如,一個四行的 DOCUMENTS 表出於文本檢索的目的有一個 KEWORDS 列和一系列相關的關鍵字。 KEYWORDS 的值是:
'database simulation analytical business intelligence' 'simulation model fruit fly reproduction temperature' 'forestry spruce soil erosion rainfall' 'forest temperature soil precipitation fire' |
在這個例子中,每列的值有 5 個子元素組成,每一個都是一個詞(關鍵詞),經過空格和其餘關鍵詞分隔開。
查詢應該在 WHERE 子句中參考這些列。
優化器會評估每一個謂詞匹配多少行。對於這些通配符 LIKE 謂詞,優化器假設 COLUMN 匹配了一系列彼此鏈接的元素,而且它基於字符串的長度來估算每一個元素的長度,除了 % 開頭或結尾的字符。若是你收集子元素的統計信息,優化器將有關於每一個子元素和分隔符的長度信息。它可使用這些額外的信息來更精確的評估可能有多少行匹配這個謂詞。
爲了鏈接子元素統計信息,運行有 LIKE STATISTICS 子句的 RUNSTATS 。
DB2 基於成本的優化器把一個基於訪問計劃處理器處理的行數 – 或基數的評估做爲這個操做的精確成本。這個基數評估是優化器成本惟一最重要的輸入,並且它的精確度很大程度上取決於 RUNSTATS 實用工具從數據庫收集的統計信息。對於計算一個精確的基數評估來講上面描述的統計信息是最重要的,然而有一些環境卻須要很是成熟的統計信息。尤爲是想要體現越複雜的關係就更須要成熟的統計信息,好比涉及比較的描述(例如,price > MSRP + Dealer_markup),關係跨了多個表(例如,product.name = 'Alloy wheels' and product.key = sales.product_key),或者其餘謂詞除了涉及獨立屬性以及簡單比較操做的謂詞。統計視圖能夠防止這些複雜關係類型,由於統計信息是在這個視圖返回值的基礎上收集的,而不是從這個視圖相關的基礎表上。
當一個查詢被編譯時,優化器把這個查詢和可用的統計視圖進行匹配。當優化器計算基數估算中間結果集時,它使用來自視圖的統計信息來計算一個更好的評估。
查詢沒必要由於優化器使用視圖就直接參考統計視圖。優化器可使用和物化查詢表(MQTs)相同的匹配機制來匹配到統計視圖的查詢。出於這個考慮,除了他們不被永久儲存,統計視圖和 MQTs 很是類似,所以它們也不消耗磁盤空間也不須要維護。
一個統計視圖在第一次建立一個視圖並使用 ALTER VIEW 語句容許優化。而後在這個統計視圖上運行 RUNSTATS,用這個視圖的統計信息填入系統編目表中。例如爲了建立一個統計視圖來表如今時間在一個星型模式中維度表和實施表之間的鏈接,執行下面語句:
CREATE VIEW SV_TIME_FACT AS ( SELECT T.* FROM TIME T, SALES S WHERE T.TIME_KEY = S.TIME_KEY) ALTER VIEW SV_TIME_FACT ENABLE QUERY OPTIMIZATION RUNSTATS ON TABLE DB2DBA.SV_TIME_FACT WITH DISTRIBUTION |
統計視圖能夠被用於對查詢提升基數評估,以及訪問計劃和查詢性能,例如:
SELECT SUM(S.PRICE) FROM SALES S, TIME T, PRODUCT P WHERE T.TIME_KEY = S.TIME_KEY AND T.YEAR_MON = 200712 AND P.PROD_KEY = S.PROD_KEY AND P.PROD_DESC = ‘ Power drill ’ |
沒有統計視圖,優化器假設全部事實表 TIME_KEY 的值對應一個特定的時間維度 YEAR_MON 值在事實表中是統一的。然而可能銷售在 12 月特別強勁,產生比其餘月份強勁多不少的交易。
在不少狀況下,統計視圖能夠提升查詢性能,而且有一些簡單的最佳實踐能夠幫助判斷須要建立哪些統計視圖。請參考「更多閱讀」章節。
自動收集統計信息當前不能用於統計視圖。不管何時統計視圖的基礎表數據有了顯著的改動都要收集統計視圖的統計信息。
進一步改善 RUNSTATS 的時機:
對一個配置了數據庫分區功能(DPF)的數據服務器,RUNSTATS 從單個數據庫分區蒐集統計信息。若是 RUNSTATS 運行在表所在的這個數據庫分區上,統計信息將在這裏收集。若是不是,統計信息將從第這個表所在分區組的一個數據庫分區上收集。爲了保持一致的統計信息,就要確保進行鏈接的表的統計信息從相同的數據庫分區蒐集。
DB2 數據服務器支持經過對 SYSSTAT 模式下的視圖發起 UPDATE 語句手動來更新編目統計信息。這個功能對在測試系統中模擬一個生產數據庫來檢查查詢計劃,或許很是有用。爲了在其餘系統上重放,db2look 工具對抓取 DDL 和 UPDATE SYSSTAT 語句方面頗有幫助。
然而,要避免手動更新統計信息 - 意味着爲了強制執行一個特定的查詢計劃經過提供不正確的統計信息影響查詢優化器。這個實踐可能形成某些查詢的性能提高,也可能致使其餘的性能降低。在最終使用這個辦法以前,請考慮其它以前考慮過的調優方法。若是不得不使用這個方法,在這種狀況下必定要記錄原始的統計信息,若是更新統計信息形成了性能降低就須要恢復它們。
在 SAP 安裝過程當中,自動和實施統計信息是默認打開的。這就是說你不須要手動發起 RUNSTATS 。
不少 SAP 使用狀況是在第一步以及經過一個複雜的 SAP 文本查詢來訪問修改表內容。不要改變下面提到的默認設置 :
Automatic maintenance (AUTO_MAINT) = ON Automatic table maintenance (AUTO_TBL_MAINT) = ON Automatic runstats (AUTO_RUNSTATS) = ON Automatic statement statistics (AUTO_STMT_STATS) = ON Automatic statistics profiling (AUTO_STATS_PROF) = OFF Automatic profile updates (AUTO_PROF_UPD) = OFF |
使用有不均勻數據的 SAP BI 表的統計視圖
在 SAP BI snowflake 模式的表中不均勻的分佈數據可能致使並不優化的查詢訪問計劃並增長查詢時間。大多數這樣的問題是經過設置 SAP 工做負載變量 =SAP 來解決的。可是在一些例外的狀況下,當不少表互相鏈接時,統計視圖能夠被建立來爲 DB2 優化器提供更多關於值分佈的信息。
下面的例子中,事實表和客戶、請求、時間以及產品維度表進行鏈接。
大多數交易是跟 Customer #10200 完成的。所以,事實表的絕大多數行在 Dim C 列的值是 2 。這形成了在事實表的 Dim C 列上的不均勻的數據分佈。
DB2 優化器可能會在對在客戶維度有約束的查詢時候估算出錯誤的基數
能夠在維度和事實表上定義統計視圖生成額外的統計信息,DB2 優化器利用這些信息來加強基數評估並減小查詢運行時間。
在上面的例子中,下面在客戶和事實表維度上的統計視圖可能解決錯誤基數統計問題並減小查詢響應時間:
CREATE VIEW stat_view as ( SELECT cust.c, cust.customer#, cust.region, f.dimC FROM customer_ 維度 cust, fact_table fact WHERE cust.c = fact.dimC ) |
若是這個統計視圖的一個基本表發生了改動,就須要在統計視圖上更新數據庫統計信息。統計視圖不支持 DB2 自動統計信息蒐集。
SAP BI 實施了它們本身的物化查詢表,叫作 SAP BI 彙集。使用 SAP 彙集在 SAP BI 應用程序中替代通常的 DB2 物化查詢表。
若是你已經遵循了本文推薦的最佳實踐,而你相信仍然沒有達到最優的性能的話,你就能夠向 DB2 優化器提供一個明確的優化指南。
優化指南包含在一個叫作優化配置文件的 XML 文檔中。配置文件定義 SQL 語句和他們相關的優化指南。
若是你普遍的使用了優化配置文件,它們須要你付出不少的努力來維護。更重要的是,你只能使用優化配置文件來對現有 SQL 語句提升性能。下面的最佳實踐對全部的查詢持續穩定的提升查詢性能,包括將來的某些查詢。
解釋工具是用來顯示被查詢優化器用來運行一個 SQL 語句的查詢訪問計劃。它包含了用於運行 SQL 語句關於相關操做很是普遍的信息,好比計劃操做去、它們的 arguments、執行順序和成本。由於查詢訪問計劃是查詢性能中最重要的因素之一,爲了能診斷查詢性能問題,可以理解解釋工具的輸出很是重要。
解釋信息一般用於:
爲了幫助你理解查詢性能變化的緣由,須要調優先後的解釋信息,你能夠經過執行下面步驟獲得它們:
經過這個方法收集的信息,爲未來的分析提供了一個參考點。對動態 SQL 語句來講,當你第一次運行你的應用程序時,你能夠蒐集這個信息。對於靜態語句,也能夠在綁定的時候蒐集這個信息。在一個主要系統更改以前蒐集這個信息很是重要,好比安裝一個新的服務級別或 DB2 版本或者一個很大的配置改動,好比增長或刪除數據庫分區和分佈數據。這是由於這類系統更改可能形成訪問計劃的不利更改。雖然訪問計劃退步應該不多發生,可是有這些可用信息將容許更快的你解決性能退步的問題。要分析一個性能變化,把以前的信息和如今你開始分析的時候收集到的關於查詢和環境的信息進行比較。
一個簡單的例子,你的分析可能顯示索引再也不做爲訪問計劃的一部分被用到。使用 Visual Explain 或 db2exfmt 顯示的編目統計信息,你可能注意到 index 級別數遠遠高於查詢第一次綁定到數據庫的時候的值。而後你能夠選擇執行下面的某個操做:
在你執行其中某個操做以後,再檢查一下查詢計劃。若是索引再一次被使用了,這個查詢的性能可能再也不是個問題。重複這些步驟直到問題被解決。
你能夠進行一系列的操做來幫助提升查詢性能,好比校對配置參數、添加容器、和蒐集刷新編目統計信息。
在你這些方面進行了更改,若是在被訪問計劃選擇到的方面有更改的話,你可使用解釋工具來判斷影響。例如,若是你基於索引指南添加一個索引或物化查詢表(MQT),解釋數據能夠幫助你判斷是否索引或物化查詢表最終如你所指望的被用到了。
雖然解釋輸出提供了讓你判斷選中的訪問計劃的信息和成本,對一個查詢來講精確測量性能提升的惟一方法是使用基準的是技術。