我們今天主要向大家講述的是在 DB2 優化器中正確使用分布統計信息的操作步驟,我們大家都知道DB2 優化器是一種基於成本的優化器。它根據表和索引的相關統計信息作出決策。DB2 在生成統計信息時。
不但能提供基本統計信息,還允許創建所謂的分布統計信息。本文解釋什麼是分布統計信息、分布統計信息在哪些情況下尤為重要,以及應用程序開發人員應該考慮些什麼,才能使 DB2 優化器創建有效的訪問計劃。
簡介
為了執行查詢或 DML 語句(INSERT、UPDATE、DELETE),DB2 必須創建一個訪問計劃(Access plan)。訪問計劃定義按什麼順序訪問表,使用哪些索引,以及用何種連接(join)方法來關聯數據。好的訪問計劃對於 SQL 語句的快速執行至關重要。DB2 優化器可以創建訪問計劃。這是一種基於成本的優化器,這意味著它是根據表和索引的相關統計信息來作出決策的。
DB2 在生成統計信息時,不但能提供基本統計信息,還允許創建所謂的分布統計信息。不但數據庫管理員要理解分布統計信息,而且應用程序開發人員也要理解分布統計信息。應用程序開發人員必須小心謹慎,因為在某些情況下分布統計信息對於 DB2 優化器來說非常重要。
主變量或參數標記(在 Java 中為 Java.sql.PreparedStatement)的使用可能會造成阻礙,使優化器無法最大限度地利用分布統計信息。本文解釋什麼是分布統計信息、分布統計信息在哪些情況下尤為重要,以及應用程序開發人員應該考慮些什麼,才能使 DB2 優化器創建有效的訪問計劃。
基本統計信息和分布統計信息
在研究分布統計信息之前,我們先來看看基本統計信息,只要執行 RUNSTATS 即可收集這些表的相關統計信息。
表的相關統計信息:
當前使用的頁面數
包含記錄行的頁面數
溢出的行數
表中的行數(基數)
對於 MDC 表,還有包含數據的塊(block)數
表中各列的相關統計信息:
列的基數
列的平均長度
列中第二大的值
列中第二小的值
列中 NULL 值的個數
通常,執行 RUNSTATS 時,不但可以收集到關於表的統計信息,而且還可以收集到相應的索引的相關統計信息。要了解為索引而收集的統計信息,請參閱 DB2 Administration Guide: Performance - Statistical information that is collected。
觀察一個表的基本統計信息,您可以看到,DB2 優化器知道一個表由多少行組成(表的基數),以及一個列包含多少個不同的值(列的基數)。但是,還有一些信息是基本統計信息無法提供的。例如,基本統計信息不能告訴優化器一個列中某些值出現的頻率。假設表 TABLE_X 有大約 1,000,000 行,在該表上執行這樣一條查詢:
SELECT * FROM TABLE_X WHERE COLUMN_Y = 'VALUE_Z'
難道 DB2 優化器知道 TABLE_X 中有多少行滿足條件 COLUMN_Y = 'VALUE_Z' 不重要嗎?換句話說:知道這個查詢將返回 1 行、100 行、1000 行還是 10000 行有什麼不好呢?
實際上,通過基本統計信息,DB2 優化器只能估計 'VALUE_Z' 在 COLUMN_Y 中出現的頻率。在這種情況下,優化器認為所有值在 COLUMN_Y 中是平均分布的,這意味著它認為所有的值都有相同的出現頻率。如果事實碰巧如此,這樣估計並無大礙。但是,如果有些值比其他值出現得更頻繁一些(例如,如果 'VALUE_Z' 出現 900,000 次,即占所有行的 90%)。
那麼優化器不能考慮到這一點,因而生成的訪問計劃就不是最優的。而分布統計信息可以填補這一空白。分布統計信息可以提供關於數據出現頻率及其分布情況的信息,如果數據庫中存儲了很多重復值,並且數據在表中並非平均分布的時候,分布統計信息對於基本統計信息是一個重要的補充。
分布統計信息的類型 —— 頻率(frequency)統計信息和分位數(quantile)統計信息
有兩種不同類型的分布統計信息 —— 頻率統計信息和分位數統計信息。讓我們通過一個示例表來研究一下這兩種不同類型的分布統計信息。
示例表 “CARS” 表示一家汽車制造商,對於生產的每一輛汽車,在表中都有相應的一行。每輛汽車可以由它的 ID 來標識,因此 “ID” 是表 “CARS” 的主鍵(PK)。此外,表中有一個 “STATE” 列,表明汽車當前處在制造流程中的哪一步。
一輛汽車的制造流程從第 1 步開始,然後是第 2 步、第 3 步,...、第 49 步、第 50 步、第 51 步、...、第 98 步、第 99 步,一直到第 100 步 —— 第 100 步意味著汽車已經完工了。已完工的汽車所對應的行仍然保留在表中,後續流程(例如投訴管理、質量保證等)仍要用到這些行。
汽車制造商生產 10 種不同型號(“TYPE” 列)的汽車。為了簡化問題,在這個示例表中,各種汽車型號命名為 A、B、C、D、...、J。除主鍵索引(在 “ID” 列上)之外,“STATE” 列上也有一個索引(“I_STATE”),在 “TYPE” 列上還有一個索引(“I_TYPE”)。實際上,一個 “CARS” 表包含的列遠不止 “ID”、“STATE” 和 “TYPE”。為簡單起見,示例表中沒有出現其他這些列。
頻率統計信息
假設表 CARS 現在有大約 1,000,000 條記錄,不同的型號在表中出現的頻率如下所示:
表 1. 表 CARS 中 TYPE 列的頻率統計信息
- TYPE COUNT(TYPE)
- A 506135
- B 301985
- C 104105
- D 52492
- E 19584
- F 10123
- G 4876
- H 4589
- I 4403
- J 3727
型號為 A 的汽車最受購買者的青睐,因此生產的汽車中大約有 50% 是這種型號。型號 B 和型號 C 僅次於型號 A ,分別占所有汽車的 30% 和 10%。其他所有型號加在一起僅占 10%。
上面的表顯示了 “TYPE” 列的頻率統計信息。通過基本統計信息,DB2 優化器只能了解到該表包含 1,000,000 行(表的基數)和 10 種不同的值(型號),即 A 到 J。如果沒有分布統計信息,優化器會認為每種值以相同的頻率出現,大約都是出現 100,000 次。而一旦生成了關於 “TYPE” 列的分布統計信息,優化器即可了解每種型號真正的出現頻率。因此,優化器清楚各種已有型號出現的不同頻率。
優化器使用頻率統計信息來計算用於檢查相等或不等的謂詞的過濾因子。例如:
- SELECT * FROM CARS WHERE TYPE = 'H'
分位數統計信息
與頻率統計信息不同,分位數統計信息與不同值的出現頻率無關,而與一個表中有多少行小於或大於某個值(或者有多少行介於兩個值之間)相關。分位數統計信息提供關於一個列中的值是否聚合的信息。為獲得這樣的信息,DB2 假定列中的值是按升序排列的,並根據正則行間隔確定相應的值。
我們來看看表 CARS 中的 “STATE” 列,該列按升序排列。根據正則行間隔,即可確定 “STATE” 的對應值。
表 2. CARS 表中 STATE 列的分位數統計信息
- COUNT(row) STATE ASC
- 5479 1
- 54948 10
- 109990 21
- 159885 31
- 215050 42
- 265251 52
- 320167 63
- 370057 73
- 424872 84
- 475087 94
- 504298 100
- ... 100
- 1012019 100
由於已完工的汽車仍然沒有從表中刪除,因此狀態為 100 (=完工)的汽車數量比所有處於其他狀態的汽車總和還多。已完工的汽車占表中所有記錄的 50%。
注意: 在實際情況下,已完工的汽車數量甚至還要更多(例如超過 99%)。在後文中的具體例子中可看到這種情況。
上表顯示了 “STATE” 列的分位數統計信息。有了這種關於有多少行分別小於和大於確定值的信息,DB2 優化器即可計算出用於測試小於(小於等於)、大於(大於等於)或介於兩值之間的謂詞的過濾因子。例如:
- SELECT * FROM CARS WHERE STATE < 100
- SELECT * FROM CARS WHERE STATE BETWEEN 50 AND 70
根據已有的分位數統計信息計算出來的過濾因子不是很精確,但即使只收集 20 個值,其誤差仍然低於 5%。