一、 動態採樣 Dynamic Sampling
1. 引入原因
oracle默認認爲where條件中出現的各列彼此是沒有關聯的,以此估算出的基數值可能不準,導致選錯執行計劃。
例如學生表有10000行,要查詢9月出生並且是處女座的人數,如果當作這兩個條件沒有關聯,默認的概率計算方法是(1/12) * (1/12) = 1/144,預估的返回值約爲69。但是顯然這兩個條件是有關聯的,9月出生的人大多都是處女座,實際返回行數應該遠大於69,而錯誤的基數預估,就可能導致選錯執行計劃。
爲了較準確地估算where條件中出現有關聯關係的列時所有條件組合的選擇率,進而得到較準確的基數值,9i R2版本引入了動態採樣技術。另外動態採樣可以在一定程度上解決因沒有統計信息而導致CBO選錯執行計劃的問題。
12c開始,該特性改名叫做 動態統計信息(Dynamic statistics)
2. 動態採樣原理
不同的應用、規則千差萬別,oracle如何能判斷各列間的關係,較準確地得出基數值?
其實,oracle在生成執行計劃前,採樣選取了表中部分數據塊,對採樣的數據塊實際執行了一次目標sql,這樣就能得到這部分數據塊的實際返回結果,而它又能通過數據字典查到表中總數據塊數,根據這個比例放大實際執行結果,這個結果就可以作爲目標sql較準確的基數值。
因此,只要目標表數據分佈相對均勻,oracle就能做到無論各列間有什麼關係,都能較準確地估算基數值。
注意,動態採樣僅適合單表或多表關聯的第一個驅動表的select,update,delete語句。如果對多表使用動態採樣,oracle無法判斷採樣哪些數據塊更有代表性,可能導致判斷錯上加錯。
3. 啓用方法
啓用方法有兩種:
- 設置參數 optimizer_dynamic_sampling 的值>=1,10gR2以上版本默認值爲2,即默認是開啓的。
- 使用動態採樣hint:dynamic_sampling(t,level),這裏的level對應上面的參數值。
select /*+ dynamic_sampling(t,2) */ * from t where n1=3 and n2=2 and c1='a'
optimizer_dynamic_sampling 參數值含義如下(以下參考自12.1文檔):
其中默認採樣數據塊數由_optimizer_dyn_smp_blks隱含參數控制,默認爲32。
Level | 含義 | 默認採樣數據塊數 (Blocks) |
---|---|---|
0 |
不啓用 |
n/a |
1 |
對沒有統計信息且滿足以下條件的表啓用
|
32 |
2 |
默認值,對沒有統計信息的表啓用動態採樣 |
64 |
3 |
滿足以下任意條件時啓用:
|
64 |
4 |
滿足以下任意條件時啓用:
|
64 |
5 |
The criteria are identical to level 4, but the database uses a different sample size. |
128 |
6 |
The criteria are identical to level 4, but the database uses a different sample size. |
256 |
7 |
The criteria are identical to level 4, but the database uses a different sample size. |
512 |
8 |
The criteria are identical to level 4, but the database uses a different sample size. |
1024 |
9 |
The criteria are identical to level 4, but the database uses a different sample size. |
4086 |
10 |
The criteria are identical to level 4, but the database uses a different sample size. |
All blocks |
11 |
12c新增等級,在優化器認爲oracle需要動態採樣數據時自動收集 |
Automatically determined |
二、 多列統計信息 MultiColumn Statistics
1. 簡介
實際上處理where條件中出現有關聯關係的列時不止一種解決方案,11g開始,oracle引入了多列統計信息,也稱爲組合列統計信息 Column Group Statistics。
11g開始,可以人爲指定存在關係的一組列爲目標表上的一個組合列,然後使用dbms_stats包對這個組合列收集統計信息,收集到的就是所謂多列統計信息。收集完成後,CBO自然也就知道了組合列的數據分佈情況。
2. 使用案例
創建cust_state_province和country_id列的Column Group
DECLARE
cg_name varchar2(30);
BEGIN
cg_name := dbms_stats.create_extended_stats(null,'customers','(cust_state_province,country_id)');
END;
/
查看column group name
select sys.dbms_stats.show_extended_stats_name('sh','customers','(cust_state_province,country_id)') col_group_name from dual;
COL_GROUP_NAME
--------------------------------------------------------------------------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_
通過sys.col$基表可以看到,組合列其實就是在該表中多加了一列,列名爲column group name,類似oracle的函數索引。可以從dba_stat_extentions視圖中查詢目標表所有組合列信息。
--查詢多列統計信息
Select extension_name, extension from user_stat_extensions where table_name='CUSTOMERS';
EXTENSION_NAME EXTENSION
------------------------------ ----------------------------------------
SYS_STU#S#WF25Z#QAHIHE#MOFFMM_ ("CUST_STATE_PROVINCE","COUNTRY_ID")
--查看distinct數和柱狀圖使用情況
select e.extension col_group, t.num_distinct, t.histogram
from user_stat_extensions e, user_tab_col_statistics t
where e.extension_name = t.column_name
and e.table_name = t.table_name
and t.table_name = 'CUSTOMERS';
COL_GROUP NUM_DISTINCT HISTOGRAM
---------------------------------------- ------------ ---------------
("CUST_STATE_PROVINCE","COUNTRY_ID") 145 FREQUENCY
收集多列統計信息
--收集已存在的列組統計信息
EXEC DBMS_STATS.GATHER_TABLE_STATS('SH','CUSTOMERS',METHOD_OPT =>'FOR ALL COLUMNS SIZE AUTO');
--收集新指定的列組統計信息
EXEC DBMS_STATS.GATHER_TABLE_STATS('SH','CUSTOMERS',METHOD_OPT =>'FOR ALL COLUMNS SIZE SKEWONLY FOR COLUMNS (CUST_STATE_PROVINCE,COUNTRY_ID) SIZE SKEWONLY');
刪除Column Group
exec dbms_stats.drop_extended_stats('sh','customers','(cust_state_province,country_id)');
參考
https://docs.oracle.com/database/121/TGSQL/tgsql_astat.htm#TGSQL453
https://docs.oracle.com/database/121/REFRN/GUID-43655FC3-3C32-486B-8B11-8C20C152618D.htm#REFRN10140