對象統計信息的作用是幫助查詢優化器選擇更好的執行計劃。
比如,某一個表的索引clustering_factor非常的高,這個時候如果在where條件中指定column between A and B的限定條件來查詢,那麼查詢優化器有兩個選擇,一個是通過索引做索引範圍掃描,另一個是全表掃描。
因爲我們知道clustering_factor的值非常高,這時候做索引範圍掃描的開銷可能還會比全表掃描更高。所以我們期望是全表掃描。
但是如果數據庫中沒有關於這個索引數據對象的統計信息,那麼查詢優化器就不會瞭解到這個索引的 clustering_factor很高,那麼查詢優化器就有可能選擇索引範圍掃描的執行計劃,這樣就會產生一個低效的執行計劃。 所以我們可以看到,對象的統計信息的重要。
下面瞭解一下對象的統計信息。
1. 對象統計信息有哪幾種類型
有三種類型的對象統計信息:表統計,列統計,索引統計。
對象 |
表/索引級別統計 |
分區級別統計 |
子分區級別統計 |
表 |
user_tab_statistics user_tables |
user_tab_statistics user_tables |
user_tab_statistics user_tables |
列 |
user_tab_col_statistics user_tab_histograms |
user_part_col_statistics user_part_histograms |
user_subpart_col_statistics user_subpart_histograms |
索引 |
user_ind_statistics user_indexes |
user_ind_statistics user_ind_partitions |
user_ind_statistics user_ind_subpartitions |
爲了測試,我們創建如下表並手動蒐集統計信息。
CREATE TABLE t AS SELECT ROWNUM AS id, ROUND(DBMS_RANDOM.normal*1000) AS val1, 100+ROUND(LN(ROWNUM/3.25+2)) AS val2, 100+ROUND(LN(ROWNUM/3.25+2)) AS val3, DBMS_RANDOM.string('p',250) AS pad FROM all_objects WHERE ROWNUM<=1000 ORDER BY dbms_random.value;
UPDATE t SET val1=NULL WHERE val1<0; ALTER TABLE t ADD CONSTRAINT t_pk PRIMARY KEY(id); CREATE INDEX t_val1_i ON t(val1); CREATE INDEX t_val2_i ON t(val2);
BEGIN dbms_stats.gather_table_stats( ownname => 'SYS', tabname =>'T', method_opt => 'for all columns size skewonly', cascade => TRUE); END;
|
下面詳細說一下表,列,索引的統計信息。
1.1 表統計信息
表統計信息從user_tab_statistics中可以得到。
SELECT
num_rows,blocks,empty_blocks,avg_space,chain_cnt,avg_row_len
FROM
user_tab_statistics
WHERE
table_name = 'T';
這裏要注意的是empty_blocks表示高水位以上的數據塊,這裏爲0,因爲dbms_stat不計算其值。Avg_space表示數據塊平均空閒空間(字節),這裏也不計算,設置爲0。Chain_cnt 行鏈接和航遷移總數,也不計算設置爲零。Avg_row_len table中平均行的長度(字節)。
1.2 列統計信息
列統計信息有兩種,普通列統計信息和直方圖。先看一下普通列統計信息。
普通列統計信息
SELECT column_name, num_distinct, low_value, high_value, density, num_nulls, avg_col_len, histogram,num_buckets FROM user_tab_col_statistics WHERE table_name ='T'; |
Num_distinct 該列中唯一值的數量。
Low_value 該列的最小值,存儲爲oracle內部格式,對字符串至存儲前32字節。
High_value 該列的最大值,存儲爲oracle內部格式,對字符串至存儲前32字節。
Density 0到1之間的一個小數。接近0表示對該列的過濾可以過濾掉大多數行(選擇性較強),接近1表示選擇性較弱。沒有直方圖的話其值爲1/num_distinct。如果有直方圖,則根據直方圖計算。
Histograms 是否有直方圖,如果有是那種類型。
Num_buckets 直方圖裏桶數。沒有直方圖則桶數爲1,最大桶數爲254。
直方圖
查詢優化器原則上認爲數據是均勻分佈的,就如表t的主鍵列id。這一列的值分佈很均勻,在1到1000上平均分布。然而有時數據的分佈並不均勻。那麼這時查詢優化器需要額外的信息才能做出正確的判斷。比如我們已經知道了val2列的數據分佈如下:
SQL> SELECT val2 as val2,count(*) FROM t GROUP BY val2 ORDER BY val2;
VAL2 COUNT(*) ---------- ---------- 101 8 102 25 103 68 104 185 105 502 106 212
6 rows selected |
如果有一條查詢語句以val2=105做過濾條件,這時查詢優化器如何選擇訪問路徑?很可能查詢優化器會選擇索引掃描,因爲它並不知道這一列值爲105的佔了一半還多。如果查詢優化器知道了這個信息,那麼它就可以果斷的選擇全表掃描,因爲在返回大量數據的情況下,全表掃描比索引開銷更小。(當然,本例中t表一共纔有1000條數據,所以無論是全表還是索引掃描都會很快返回結果)
要獲得這些額外信息,查詢優化器可以查詢直方圖。直方圖有兩種,頻率直方圖和等高直方圖。他們的區別主要在於桶數和唯一值的個數。直方圖的桶數最大爲254。如果唯一值的個數小於等於254就可以建立頻率直方圖,每一個唯一值一個桶。如果唯一值的個數大於254則要建立等高直方圖。
頻率直方圖,下面的查詢查詢了表t val2列上的頻率直方圖。
SQL> SELECT endpoint_value, 2 endpoint_number, 3 endpoint_number - lag(endpoint_number,1,0) OVER (ORDER BY endpoint_number) AS frequency 4 FROM user_tab_histograms 5 WHERE table_name='T' AND column_name='VAL2' 6 ORDER BY endpoint_number 7 /
ENDPOINT_VALUE ENDPOINT_NUMBER FREQUENCY -------------- --------------- ---------- 101 8 8 102 33 25 103 101 68 104 286 185 105 788 502 106 1000 212
6 rows selected |
從上面的查詢可以瞭解到,endpoint_value代表的是直方圖中桶內唯一值的內容。Endpoint_number存儲的是頻率。不過這個頻率是累加頻率。
等高直方圖,下面的語句手動建立了一個等高直方圖。
SQL> SELECT count(*) , max(val2) AS endpoint_value , endpoint_number 2 FROM (SELECT val2, ntile(5) over(order by val2) as endpoint_number FROM t) 3 GROUP BY endpoint_number 4 ORDER BY endpoint_number 5 /
COUNT(*) ENDPOINT_VALUE ENDPOINT_NUMBER ---------- -------------- --------------- 200 104 1 200 105 2 200 105 3 200 106 4 200 106 5
|
關於直方圖的信息這裏講述的很不完全,需要查看額外的文檔具體瞭解。
1.3 擴展列的統計信息
如果我們在where條件中這樣使用一個查詢條件upper(val2) = 105,那麼查詢優化器是無法使用統計信息的。而相應的我們可以這樣處理,創建一個upper(val2)的虛列,然後在這個虛列上收集統計信息。不過我們要了解的下面的這個函數可以幫我們完成從創建虛列到收集虛列統計信息的全過程。
SELECT dbms_stats.create_extended_stats(ownname => 'SYS',tabname => 'T',extension => '(UPPER(PAD))') FROM DUAL; |
1.4 索引統計信息
SQL> SELECT INDEX_NAME, 2 BLEVEL, 3 LEAF_BLOCKS, 4 DISTINCT_KEYS, 5 NUM_ROWS, 6 CLUSTERING_FACTOR 7 FROM DBA_IND_STATISTICS WHERE TABLE_NAME='IND_GOOD'; |
上面主要講解了各種類型的統計信息,以及如何查詢這些統計信息,下面講解一下怎樣生成這些統計信息。
2. 收集對象統計信息
收集統計信息要用dbms_stats工具包來收集。裏面提供了多個過程:
Gater_database_stats
Gather_dictionary_stats
Gather_fixed_objects_stats
Gather_schema_stats
Gather_table_stats
Gather_index_stats
這些存儲過程每個都需要多個參數,這些參數可以分成三大組,第一組,指明對象,第二組,指明收集選項,第三組指明覆蓋當前的統計信息之前是否備份。
參數 |
數據庫 |
數據字典 |
固定對象 |
模式 |
表 |
索引 |
目標對象 |
|
|
|
|
|
|
Owner |
|
|
|
√ |
√ |
√ |
Indname |
|
|
|
|
|
√ |
tabname |
|
|
|
|
√ |
|
partname |
|
|
|
|
√ |
√ |
Comp_id |
|
√ |
|
|
|
|
granularity |
√ |
√ |
|
√ |
√ |
√ |
cascade |
√ |
√ |
|
√ |
√ |
|
Gather_sys |
√ |
|
|
|
|
|
Gather_temp |
√ |
|
|
√ |
|
|
options |
√ |
√ |
|
√ |
|
|
objlist |
√ |
√ |
|
√ |
|
|
force |
|
|
|
√ |
√ |
√ |
Obj_filter_list |
√ |
√ |
|
√ |
|
|
收集選項 |
|
|
|
|
|
|
Estimate_percent |
√ |
√ |
|
√ |
√ |
√ |
Block_sample |
√ |
√ |
|
√ |
√ |
|
Method_opt |
√ |
√ |
|
√ |
√ |
|
No_invalidate |
√ |
√ |
√ |
√ |
√ |
|
備份表 |
|
|
|
|
|
|
Stattab |
√ |
√ |
√ |
√ |
√ |
√ |
Statid |
√ |
√ |
√ |
√ |
√ |
√ |
statown |
√ |
√ |
√ |
√ |
√ |
√ |
下面介紹一下這些參數的意義。
目標對象參數:
Ownname 指定schema名稱。
Indname 指定索引名稱。
Tabname 指定表的名稱
Partname 指定分區或者子分區的名稱。如果不指定,則收集所有分區的對象統計信息。
Comp_id 這個不明確。
Granularity 指定要處理的分區對象的統計級別。
Cascade 指明是否手機索引統計信息。
Gather_sys 指明是否手機sys用戶統計信息
Gather_temp 指明是否收集臨時表的統計信息。但要注意的是,dbms_stats運行時,會先commit,所以只有指定了on commit preserve rows的臨時表纔可以被處理。
Options 包含7個選項
Gather: 處理所有對象
Gatherauto 由系統決定那些對象要處理以及如何處理
Gatherstale 只處理信息失效的對象,注意,沒有統計信息的不算信失效。
Gatherempty 只處理沒有統計信息的對象
List auto 列出將用gather auto處理的對象
Liststale 列出將用gather stale處理的對象
Listempty 列出將用gather empty處理的對象
Objlist 該參數根據options的不同值返回被處理的對象列表。
Obj_filter_list 在目標對象滿足該參數指定的過濾條件時纔會收集統計信息
收集選項參數:
Estimate_percent指明是否採樣收集統計信息。值可以爲0.0000001到100。一百表示不採樣。常量 dbms_stats.auto_sample_size算作0,由系統決定採樣大小。
Block_sample 指明採樣是採用數據行採樣還是數據塊採樣。行採樣精確,塊採樣快捷。
Method_opt 指明是否收集直方圖統計信息還指明採樣的最大桶數。
值的格式爲columns clause + size clause
例如:for all columns size skewonly
Columnsclause可取值有:
for all [indexed / hidden ] columns
Sizeclause 可取值有:
size 1-254
Size skewonly 只收集skew列,桶數由系統決定
Size auto 同上,並且要加上where引用的列
Size repat 只是刷新現有直方圖
No_invalidate 收集了統計信息,很有可能有一些遊標就不適用了。那麼這時這個參數可以指定成三個值。
True遊標不失效,這樣重新收集統計信息就沒意義了。
False遊標立即失效,可能會造成集中大量解析遊標
Dbms_stats.auto_invalidate遊標不立即失效,這樣可以避免集中解析問題。
備份表參數
Stattab 指定存儲統計信息的備份表
Statid
Statown 指定備份表的用戶名,默認是當前用戶。