現在,幾乎所有重要數據庫都使用某種方法來更新目錄統計信息,以便為其優化器提供可能的最佳信息。可以將優化器視為一個勘探器,正在系統中的數據所代表的大山中進行定位。目錄統計信息的更新將為優化器提供最新的地圖,以便在整個地形中快速定位。
DB2 優化器使用目錄統計信息來確定最佳的訪問路徑,而更新這些目錄統計信息所采用的主要方法就是運行 RUNSTATS 實用程序。當用戶表中發生數據修改時,目錄統計信息表不會自動被修改。必須在表和索引上執行 RUNSTATS 命令,用最新的信息更新目錄表中的列。
可以查詢下列目錄列,確定是否在表和索引上執行了 RUNSTATS:
- 如果對于某個表,SYSCAT.TABLES 視圖的 CARD 列顯示的值為 -1,或者 STATS_TIME 列顯示的值為 NULL,那么這表示沒有對該表運行 RUNSTATS 實用程序。
- 如果對于某個索引,SYSCAT.INDEXES 視圖的 NLEAF、NLEVELS 和 FULLKEYCARD 列顯示的值為 -1,或者 STATS_TIME 列顯示的值為 NULL,那么這表示沒有對該索引運行 RUNSTATS 實用程序。
在第一次將數據載入到表中之后,就無法避免地要對表進行更新、刪除和插入等形式的修改。可以添加或刪除索引。特定列中的數據分布可能隨時間發生改變。目錄中不會反映這些修改,除非在這些表和索引上執行 RUNSTATS。一段時間之后,隨著表和數據發生更改,目錄統計信息可能會過時。
執行 RUNSTATS 是很重要的,但是頻繁地運行可能會帶來問題。對于較小的表,發出 RUNSTATS 命令將是一項普通任務。然而,隨著表的增長,完成 RUNSTATS 命令將占用更多時間、CPU 和內存資源。最終,您必須考慮分配更多時間和資源來運行 RUNSTATS 與不執行該命令的潛在性能下降之間的平衡。通常只在關鍵查詢的速度開始減慢時,管理員才會對 RUNSTATS 給予適當的注意。您可以通過制定高效、有效收集統計信息的策略,避免未經思考就調優查詢和執行 RUNSTATS。
理論上,應該在下列情況下對表和索引執行 RUNSTATS:
- 將數據載入表中并創建了合適的索引之后。不過,最好是在創建索引之后再執行 LOAD 命令,并在 LOAD 期間收集統計信息。
- 創建了一個新的索引之后。
- 使用 REORG 實用程序重新組織表之后。
- 通過數據更新、刪除和插入大量更新表及其索引之后。
- 更改了預取(prefetch)大小之后。
- 運行 REDISTRIBUTE DATABASE PARTITION GROUP 實用程序之后。
您可以通過比較查詢 RUNSTATS 之前和之后的 EXPLAIN 輸出,來確定運行 RUNSTATS 對于訪問計劃的影響。
完成每一條 RUNSTATS 語句之后,您都應該執行顯式的 COMMIT WORK。COMMIT 將釋放鎖,并避免在收集多個表的統計信息時填寫日志。
在用 RUNSTATS 收集了統計信息之后,要使用 BIND 命令或 REBIND 命令重新綁定包含了靜態 SQL 的包(并可以選擇重新解釋其語句)。 db2rbind
命令可用于重新綁定數據庫中的所有包。使用 FLUSH PACKAGE 命令來刪除包緩存器中當前所有緩存的動態 SQL 語句,并強制隱式地編譯下一請求。
注意:在 RUNSTATS 語法中,必須使用全限定的表名 schema.table-name
和全限定的索引名 schema.index-name
。您可以在所有列上,或者僅僅在某些列或列組(除了 LONG 和 LOB 列)上執行 RUNSTATS。如果沒有指定特定列的子句,系統則會使用默認的 ON ALL COLUMNS 子句。
當您已確定表中包含不是統一分布的數據時,可以運行包含 WITH DISTRIBUTION 子句的 RUNSTATS。目錄統計信息表通常包含關于表中最高和最低值的信息,而優化器假定數據值是在兩個端點值之間均勻分布的。然而,如果數據值彼此之間差異較大,或者群集在某些點上,或者是碰到許多重復的數據值,那么優化器就無法選擇一個最佳的訪問路徑,除非收集了分布統計信息。使用 WITH DISTRIBUTION 子句還可以幫助查詢處理沒有參數標志符(parameter marker)或主機變量的謂詞,因為優化器仍然不知道運行時的值是有許多行,還是只有少數行。
在執行包含 WITH DISTRIBUTION 子句的 RUNSTATS 時,會根據 RUNSTATS 命令中給定的選項選擇一組頻率(frequency)和分位數(quantile)的統計信息。
RUNSTATS 收集兩種類型的數據分布統計信息:頻率統計信息和分位數統計信息。
頻率統計信息的默認值由 num_freqvalues 數據庫配置參數控制,該值提供了重復最多的列和數據值的信息。其默認值是 10,建議將這個值設置在 10 到 100 之間。如果將 num_freqvalues 設置為零,則不保留任何頻率值的統計信息。
分位數統計信息的默認值由 num_quantiles 數據庫配置參數控制,該值提供了數據值對于其他值而言是如何分布的有關信息。 num_quantiles 數據庫配置參數指定應將列數據值分成的組數。其默認值是 20,建議將該值設置在 20 到 50 之間。如果將這個參數設置為零或“1”,則不收集任何分位數統計信息。
如果沒有在 RUNSTATS 命令的列或表級別上指定 num_freqvalues 和 num_quantiles,那么 num_freqvalues 的值將從 num_freqvalues 數據庫配置參數中獲取,而 num_quantiles 的值將從 num_quantiles 數據庫配置參數中獲取。
可以為單個列或一組列修改頻率和分位數統計信息的精確度。提高分布統計信息的精確度將導致更大的 CPU 和內存消耗,并占用更多的目錄空間。對于這些分布統計信息,只考慮對擁有選擇謂詞的最重要的查詢而言最為重要的列。
當出現下列任何一種條件時,RUNSTATS 將不收集分布統計信息:
- 當將 num_freqvalues 配置參數設置為零(0),以及將 num_quantiles 數據庫配置參數設置為零(0)或 1 時。
- 當每個數據值是惟一的時候。
- 當該列是 LONG、LOB 或結構化列時。
- 如果列中只有一個非空值。
- 擴展的索引或聲明的臨時表。
列組(Column Group)統計信息將獲得一組列的不同值組合的數目。通常,DB2 優化器可用的基本統計信息不檢測數據相關性。列組的使用將給多個謂詞的聯合選擇提供更準確的估計。列組統計信息假設數據是均勻分布的;但還無法獲得列組上的分布統計信息。
較于列組的基數,單個列的基數(cardinality)的乘積將獲得更好的相關性估計。
當在 RUNSTATS 中指定 LIKE STATISTICS 子句時,將收集附加的列統計信息。這些統計信息存儲在 SYSIBM.SYSCOLUMNS 表里的 SUB_COUNT 和 SUB_DELIM_LENGTH 列中。它們僅針對字符串列進行收集,查詢優化器用它們來提高“column LIKE '%abc'”和“column LIKE '%abc%'”類型謂詞的選擇性估計。
現在,可以在 DB2 V8.2 中為 RUNSTATS 建立一個統計信息的配置文件。統計信息配置文件是指一組選項,它預先定義了特定表上將要收集的統計信息。
當將命令參數“SET PROFILE”添加到 RUNSTATS 命令時,將在表描述符和系統目錄中注冊或存儲統計信息配置文件。若要更新該統計信息配置文件,則可以使用命令參數“UPDATE PROFILE”。
沒有刪除配置文件的選項。
隨著數據庫快速不斷地增長,通過訪問所有數據收集統計信息的能力可能會受到固定的批量窗口、內存和 CPU 約束的阻礙。
目前,要運行表上的 RUNSTATS,就要執行全表掃描。通過數據抽樣,只需掃描數據的一個子集即可。
如果一個查詢試圖預計總的趨勢和模式,且某一誤差域(margin of error)內的近似答案足以監測這些趨勢和模式,那么數據抽樣或許是比全表掃描更好的選擇。
在 DB2 V8.1 中,引入了 SAMPLED DETAILED 子句,允許通過抽樣計算詳細的索引統計信息。該子句的使用將減少為獲得詳細索引統計信息而執行的后臺計算量和所需的時間,但在大多數情況下,都會使數據足夠的精確。
帶有行級貝努里(Bernoulli)抽樣的 RUNSTATS
行級貝努里(Bernoulli)抽樣利用 sargable(search + argument-able 謂詞是一個可以由數據管理器來評估的謂詞)謂詞獲得百分之 P 的表行樣本,在樣本中包含每一行的概率是 P/100,而不包含它的概率則是 1 - P/100。
例如,對于 10% 貝努里(Bernoulli)抽樣,將會選擇 10%(10/100)的行,而拒絕 90%(1-10/100)的行。在貝努里(Bernoulli)抽樣中,每一頁將會引發一次 I/O,因為要掃描該表。將生成一個隨機數來確定是否選擇一行(類似于以 P/100 的概率扔錢幣)。即使每一頁都發生一次 I/O,我們仍然節省了處理數據所需的 CPU 時間。
在行級貝努里(Bernoulli)抽樣中,需要讀取每一個數據頁。然而,它仍然可以帶來極大的性能提高,因為 RUNSTATS 是 CPU 密集的。如果索引是可用的,那么就會改進抽樣。如果數據是群集的,它還可以提供更準確的統計信息(所獲得的樣本更好地代表了整個表數據)。
系統頁級抽樣與行級抽樣類似,除了抽樣的對象是頁面而不是行。以 P/100 的概率選擇每一頁,而以 1 - P/100 的概率拒絕頁的選擇。在所選中的每一頁中,要選擇所有的行。系統頁級抽樣優于全表掃描或貝努里(Bernoulli)抽樣的地方是它節省了 I/O。
抽樣頁也是預取的,所以該方法將比行級貝努里(Bernoulli)抽樣更快。與不進行抽樣相比,頁級抽樣極大地提高了性能。
RUNSTATS repeatable 子句允許通過 RUNSTATS 語句生成相同的樣本,只要表數據沒有發生更改。為了指定該選項,用戶還必須提供一個整數,以表示將用于生成樣本的種子(seed)。通過使用相同的種子,可以生成相同的樣本。
總之,統計信息的準確性取決于抽樣率、數據傾斜(data skew)以及用于數據抽樣的數據群集。
對于數據庫中的所有表,收集統計信息的一個可供選擇的方法就是發出一條 REORGCHK 命令
REORGCHK UPDATE STATISTICS ON TABLE ALL
雖然該方法看上去是一種在多個表上收集目錄統計信息的快速方法,但是僅僅當 REORGCHK 可以在合理的時間內完成執行時,該方法才是可取的。
在表的 LOAD REPLACE 期間以及索引的創建期間,也可以進行目錄統計信息的收集。
在 UDB V8.2 中,為了在 LOAD 期間調用目錄統計信息的收集,必須將選項“STATISTICS USE PROFILE”添加到 LOAD 控制語句中。選項“STATISTICS YES”仍然有用,但它現在已是過時的語法。若在表的 LOAD 之后在同一表上執行 RUNSTATS,那么在 LOAD 期間發出“STATISTICS USE PROFILE”的目的就是為了減少正常運行過程中占用的時間。在執行 load 之前,就必須創建統計信息配置文件,它現在允許指定與 RUNSTATS 命令中相同的統計信息選項。
為了可以對一個表或索引收集統計信息,必須能夠連接到包含該表和索引的數據庫,并具有下列授權級別之一:
- sysadm
- sysctrl
- sysmaint
- dbadm
- 表上的 CONTROL 權限
當對一個表運行 RUNSTATS 時,有兩種用戶訪問選項:允許讀訪問和允許寫訪問。
在 RUNSTATS 命令中的參數 ALLOW READ ACCESS 指定計算統計信息時,其他用戶可以只讀地訪問該表。
在 RUNSTATS 命令中的參數 ALLOW WRITE ACCESS 指定計算統計信息時,其他用戶可以讀取或寫入該表。如果該表在任何時刻都必須是可用的,那么應該使用該子句。
當在一個分區數據庫中發出 RUNSTATS 命令,并且一個表分區位于發出 RUNSTATS 的數據庫分區中時,那么 RUNSTATS 將在該數據庫分區上執行。如果表分區不在該數據庫分區上,那么將請求發送給數據庫分區組中持有該表分區的第一個數據庫分區。然后,在該數據庫分區上執行 RUNSTATS 命令。
RUNSTATS 不是在分區的數據庫中并行運行的,但對一個分區確定信息,然后對所有分區推斷出合適的估計值。有一個隱式的假設:每個表中的行是均勻分布在每個多分區數據庫分區組中的所有分區上的。
下列 IBM 技術札記(technote)談到了加載一個表時運行 RUNSTATS 可能碰到的問題。其解決方案就是確保在加載表之前,為該表定義一個分區鍵(partitioning key)。
IBM Technote # 1153232(2004-02-12):
“加載表之后,Runstats 將多分區實例上 syscat.tables 中的列 CARD 更新為零行。
摘要
如果加載某一給定表之后,其中一個分區的行數為零,并且將從該分區執行 runstats,那么該命令將更新 syscat. 表中的列 CARD,顯示該表的行數為零。這只對多分區的實例有影響。
內容
runstats 的行為使其將使用運行它的分區上的數據來推測該表中的行數。例如,如果加載之后所有數據都在一個分區上,并從另一分區執行 runstats,那么該命令將更新 syscat.tables 來表示該表的行數為零。然而,如果是從保存所有數據的分區運行 runstats,那么它將更新 syscat.tables 來展示該表包含((該分區上的行數)x(分區數目))行。
為了避免 runstats 的行為默認行為,需要在加載表之前,為該表定義分區鍵(partitioning key)。分區鍵需要位于高度惟一的一列或一組列上,從而確保數據均勻分布在該表所定義的所有分區上。”
stat_heap_sz 或統計信息堆大小的數據庫配置參數指定了使用 RUNSTATS 命令收集統計信息中所用堆的最大尺寸。它是在啟動 RUNSTATS 實用程序時分配的,然后當它完成時釋放。stat_heap_sz 是代理私有內存的一部分。因此,在收集分布統計信息時,最好增大 stat_heap_sz 參數,以便能將更多的列放入這個堆中。處理較寬的表也需要更多的內存。當執行包含 SAMPLED DETAILED 選項的 RUNSTATS 時,必須額外分配 2 MB 內存,以確保 RUNSTATS 能夠成功運行。
您可以使用下列策略來幫助減小 RUNSTATS 對于系統的性能影響:
- 一次僅在少數表和索引上運行 RUNSTATS,在整組表中循環運行。
- 僅指定將收集其數據分布統計信息的那些列。僅指定那些謂詞中所使用的列。
- 對于不同的表,在不同的分區上實現多個并發的 RUNSTATS。
- 僅在那些影響當前工作負載的關鍵表上執行 RUNSTATS。避免在不需要它的表上運行 RUNSTATS。
- 根據表中數據發生改變的速度,調整 RUNSTATS 的頻率。
- 根據 RUNSTATS 在該表上完成運行的速度,調整 RUNSTATS 的頻率和細節。
- 僅在系統活動量少的時候,安排執行 RUNSTATS。
- 調整(Throttle)RUNSTATS,以便最大程度地減少它對系統的需求。
僅在系統活動量少的時候安排執行 RUNSTATS,這是最大程度地減少系統影響的一個好方法。然而,對于一個 24 x 7 的系統,系統中可能沒有可用的窗口或活動量少的時候。處理該情形的一種方法就是使用 RUNSTATS 的 throttling 選項。
throttling 選項將根據當前的數據庫活動級別,來限制實用程序所占有的資源數量。UDB 中,在調整時,util_impact_lim 與 UTIL_IMPACT_PRIORITY 參數的交互確定了 RUNSTATS 的行為。UTIL_IMPACT_PRIORITY 關鍵字被用于諸如 RUNSTATS 的實用程序命令的子句中,而 util_impact_lim 則是一個實例配置參數。
util_impact_lim 參數是指允許所有已調整實用程序對于實例的工作負載產生影響的百分比。如果 util_impact_lim 是 100(默認值),則不用調整諸如 RUNSTATS 之類的實用程序調用。例如,如果將 util_impact_lim 設置為 10,那么已調整的 RUNSTATS 調用就被限定在消耗 10% 以下的工作負載。
UTIL_IMPACT_PRIORITY 關鍵字可充當一個開關,它指定 RUNSTATS 是否訂閱調整策略。
可以在已聲明的全局臨時表(DGTT)上發出 RUNSTATS 命令,但是結果的統計信息不存儲在系統目錄中,因為聲明的臨時表條目沒有目錄條目。這些統計信息存儲在表示聲明的臨時表的目錄信息的內存結構中。如果整個查詢經過時間中所節省的時間比完成 RUNSTATS 所增加的時間大得多,就建議發出 RUNSTATS。
可以在 SQL 例程(過程、UDF 和方法)中發出 RUNSTATS 命令嗎?
下列 IBM 技術札記(technote)討論了該問題:
IBM Technote # 1153051
“既不能從 SQL 例程(過程、UDF、方法)、SQL 動態復合語句發出 RUNSTATS 命令,也不能使用從 SQL 例程中發出的操作系統調用來發出該命令。如果需要發出 RUNSTATS 命令,那么可以直接從命令行處理器(Command Line Processor,CLP)發出它,或者通過使用 db2Runstats() API 函數(DB2 8.1 開始)從客戶機應用程序或外部語言例程發出它,以及通過 LOAD 和 CREATE INDEX 語句發出該命令。”
可以創建一個名為“runstats”的 C 存儲過程,調用 db2Runstats() API 函數。然后,可以使用 CALL 命令調用這個 C 存儲過程。
如何通過調用級接口(CLI)或 Java 執行 RUNSTATS 來收集統計信息?
下列 IBM 技術札記回答了該問題:
IBM Technote # 1023788:
“DB2 管理 API(編程接口)sqlustat 可以用于從 DB2 應用程序發出 RUNSTATS,例如寫入調用級接口的應用程序。DB2 Administrative API Reference 手冊中描述了 sqlustat。”
DB2 自動統計信息收集是在 DB2 UDB Version 8.2 中引入的。自動統計信息收集是完全自動表維護解決方案的一部分。其目標是允許 DB2 確定工作負載需要哪些統計信息,并定期在后臺自動運行 RUNSTATS 實用程序,以便按需更新統計信息。
為了設置 SAMPLE 數據庫自動進行統計信息收集,需要為自動維護開關設置數據庫配置參數,如下所示:
|
下圖(只顯示統計信息收集和配置選項)展示了統計信息收集和配置的自動維護命令的層次結構和相關性。在該結構中,可以在最高層次快速關閉自動維護參數 AUTO_MAINT,而不丟失較低層的配置設置,比如 AUTO_RUNSTATS。
如果需要自動統計信息配置,那么可以打開參數 AUTO_STATS_PROF 和 AUTO_PROF_UPD。自動統計信息配置則通過確定何時和如何收集統計信息更進了一步。統計信息配置文件是自動生成的,自動統計信息收集過程將用它來調度 RUNSTATS。可以用內部算法來比較新收集的統計信息與已保存的一組統計信息,并基于某些觸發條件發出包含抽樣的 RUNSTATS。
當啟用自動統計信息配置時,數據庫活動的有關信息被收集并存儲在查詢反饋倉庫中。然后,基于查詢反饋倉庫中的數據生成統計配置文件。
為了允許自動生成統計信息配置文件,需要設置兩個數據庫配置參數:
- db2 update db cfg for SAMPLE using AUTO_STATS_PROF ON
打開該參數將啟動查詢反饋數據的收集。
- db2 update db cfg for SAMPLE using AUTO_PROF_UPD ON
打開該參數,指定使用分析查詢反饋數據的 DB2 中的建議來更新 RUNSTATS 配置文件。
在觸發自動統計信息配置之前,必須通過運行 SYSINSTALLOBJECTS 存儲過程創建查詢反饋倉庫。
按照下列方式調用該存儲過程:
|
其中,toolname 是“ASP”或“AUTO STATS PROFILING”,對于 action,“C”表示創建,“D”表示刪除。
目前,不使用參數 schemaname。
例如,要創建反饋倉庫,需要運行下列存儲過程:
|
該過程將創建下列表、存儲建議以及與查詢執行過程中碰到的謂詞有關的信息:
- SYSTOOLS.OPT_FEEDBACK_QUERY
- SYSTOOLS.OPT_FEEDBACK_PREDICATE
- SYSTOOLS.OPT_FEEDBACK_PREDICATE_COLUMN
- SYSTOOLS.OPT_FEEDBACK_RANKING
- SYSTOOLS.OPT_FEEDBACK_RANKING_COLUMN
當禁用 AUTO_PROF_UPD 參數時,可以將建議存儲在 SYSTOOLS.OPT_FEEDBACK_RANKING 表中。然后,當手動更新 RUNSTATS 配置文件時,就可以查看該表中所存儲的建議。
DB2 自動統計信息收集和配置生成只能在 DB2 串行模式下啟用;它們在聯邦的、SMP 和 MPP 環境中是不可用的