1. 程式人生 > >ORACLE直方圖(10g)

ORACLE直方圖(10g)

values reat user 好的 創建 ogr dbm ams oracle

為什麽需要直方圖 ?當表中一列數據比較的值分布比較均勻時,optimzer可以很好的通過最大值,最小值和NDV(唯一值的個數),就可以判斷出cardinality.對於cardinality越精確,optimzer就可以更加好的選擇執行計劃。

--創建測試表並插入數據

create table t1(a int,b varchar2(100));

begin

for i in 1..100 loop

insert into t1 values (1,‘abcd‘);

end loop;

commit;

end;

/

begin

for i in 1..100 loop

insert into t1 values (2,‘efg‘);

end loop;

commit;

end;

/

---收集統計信息

exec dbms_stats.gather_table_stats(tabname => ‘t1‘,ownname => user,method_opt => ‘for all columns size 1‘); --for all columns size 1 不收集直方圖信息

---執行一個語句來看看optimizer評估的行

explain plan for select * from t1 where a=1;

select * from table(dbms_xplan.display());

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 100 | 700 | 3 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| T2 | 100 | 700 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------

返回100行,說明優化器在這種數據平均分布的情況下評估很準確。現在insert into t1 values(3,‘mnb‘); 一行,人為的模擬數據分布不均,再次收集統計信息

explain plan for select * from t1 where a=3;

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1513984157

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 67 | 469 | 3 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| T2 | 67 | 469 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------

優化器評估為67行.計算公式為 rows/ndv=(200/3)=66.66666

看看收集了集方圖後的結果

SQL> exec dbms_stats.gather_table_stats(tabname => ‘T1‘,ownname => user,method_opt => ‘FOR ALL COLUMNS SIZE AUTO‘);

SQL> explain plan for select * from t1 where a=3;

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1513984157

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 7 | 3 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| T2 | 1 | 7 | 3 (0)| 00:00:01 |

--------------------------------------------------------------------------

可以看出通過增加了直方圖,oracle比較準確的評估了cardinality。

SQL> select column_name,histogram from user_tab_col_statistics where table_name=‘T2‘;

COLUMN_NAME HISTOGRAM

------------------------------ ---------------

A FREQUENCY --頻率直方圖

B NONE

直方圖分為兩種頻率直方圖和高度平衡直方圖

直方圖的限制:1,收集直方圖有開銷,如cpu和磁盤空間;2,對於每個欄位超過254的distinct value,頻率直方圖的作用開始下降

隨著NDV的增加,精度進一步下降,這時候只能使用高度平衡直方圖.3,對於字符類型,只能收集前32個字節;

4,在非索引的欄位上收集直方圖的效果有限.

高度平衡和頻率直方圖的選擇:對於某個欄位的NDV小於所定義的桶數,使用頻率直方圖,否則使用高度平衡直方圖。兩種方式的最大的桶數為254,

SQL> create table t2(a int);

begin

for i in 1..76 loop

insert into t2 values (i);

end loop;

commit;

end;

/

SQL> select count(distinct a) from t2; --insert 76種不同的值

COUNT(DISTINCTA)

----------------

76

SQL> exec dbms_stats.gather_table_stats(tabname => ‘T2‘,ownname => user,method_opt => ‘FOR COLUMNS A SIZE 75‘);

人為的定義桶數小於NDV,在這種條件,oracle會使用高度平衡直方圖,因為頻率直方圖75個bucket容不下76

SQL> select column_name,histogram from user_tab_col_statistics where table_name=‘T2‘;

COLUMN_NAME HISTOGRAM

------------------------------ ---------------

A HEIGHT BALANCED

對於頻率直方圖,如果NDV小於254的情況,ndv應該是和桶數相等的.有些bug會產生不一致,導致評估不準確,具體可以參考metalink的相關bug。

SQL> select count(b.endpoint_value) from user_histograms b where table_name=‘T1‘ and column_name=‘A‘;

COUNT(B.ENDPOINT_VALUE)

-----------------------

3

SQL> select table_name,column_name,num_distinct from user_tab_col_statistics where table_name=‘T1‘ and column_name=‘A‘;

TABLE_NAME COLUMN_NAME NUM_DISTINCT

------------------------------ ------------------------------ ------------

T2 A 3

一般建議的收集方法為‘FOR ALL COLUMNS SIZE AUTO‘,除非有很好的理由去更改,由oracle自行決定是否需要histogram和桶數

為什麽需要直方圖 ?當表中一列數據比較的值分布比較均勻時,optimzer可以很好的通過最大值,最小值和NDV(唯一值的個數),就可以判斷出cardinality.對於cardinality越精確,optimzer就可以更加好的選擇執行計劃。
--創建測試表並插入數據create table t1(a int,b varchar2(100));beginfor i in 1..100 loopinsert into t1 values (1,‘abcd‘);end loop;commit;end;/beginfor i in 1..100 loopinsert into t1 values (2,‘efg‘);end loop;commit;end;/---收集統計信息exec dbms_stats.gather_table_stats(tabname => ‘t1‘,ownname => user,method_opt => ‘for all columns size 1‘); --for all columns size 1 不收集直方圖信息
---執行一個語句來看看optimizer評估的行explain plan for select * from t1 where a=1;select * from table(dbms_xplan.display());--------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 100 | 700 | 3 (0)| 00:00:01 ||* 1 | TABLE ACCESS FULL| T2 | 100 | 700 | 3 (0)| 00:00:01 |--------------------------------------------------------------------------返回100行,說明優化器在這種數據平均分布的情況下評估很準確。現在insert into t1 values(3,‘mnb‘); 一行,人為的模擬數據分布不均,再次收集統計信息explain plan for select * from t1 where a=3;PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------Plan hash value: 1513984157--------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 67 | 469 | 3 (0)| 00:00:01 ||* 1 | TABLE ACCESS FULL| T2 | 67 | 469 | 3 (0)| 00:00:01 |--------------------------------------------------------------------------優化器評估為67行.計算公式為 rows/ndv=(200/3)=66.66666看看收集了集方圖後的結果SQL> exec dbms_stats.gather_table_stats(tabname => ‘T1‘,ownname => user,method_opt => ‘FOR ALL COLUMNS SIZE AUTO‘);SQL> explain plan for select * from t1 where a=3;PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------Plan hash value: 1513984157--------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 7 | 3 (0)| 00:00:01 ||* 1 | TABLE ACCESS FULL| T2 | 1 | 7 | 3 (0)| 00:00:01 |--------------------------------------------------------------------------可以看出通過增加了直方圖,oracle比較準確的評估了cardinality。SQL> select column_name,histogram from user_tab_col_statistics where table_name=‘T2‘;COLUMN_NAME HISTOGRAM------------------------------ ---------------A FREQUENCY --頻率直方圖B NONE直方圖分為兩種頻率直方圖和高度平衡直方圖直方圖的限制:1,收集直方圖有開銷,如cpu和磁盤空間;2,對於每個欄位超過254的distinct value,頻率直方圖的作用開始下降隨著NDV的增加,精度進一步下降,這時候只能使用高度平衡直方圖.3,對於字符類型,只能收集前32個字節;4,在非索引的欄位上收集直方圖的效果有限.高度平衡和頻率直方圖的選擇:對於某個欄位的NDV小於所定義的桶數,使用頻率直方圖,否則使用高度平衡直方圖。兩種方式的最大的桶數為254,SQL> create table t2(a int);beginfor i in 1..76 loopinsert into t2 values (i);end loop;commit;end;/SQL> select count(distinct a) from t2; --insert 76種不同的值COUNT(DISTINCTA)---------------- 76SQL> exec dbms_stats.gather_table_stats(tabname => ‘T2‘,ownname => user,method_opt => ‘FOR COLUMNS A SIZE 75‘);人為的定義桶數小於NDV,在這種條件,oracle會使用高度平衡直方圖,因為頻率直方圖75個bucket容不下76SQL> select column_name,histogram from user_tab_col_statistics where table_name=‘T2‘;COLUMN_NAME HISTOGRAM------------------------------ ---------------A HEIGHT BALANCED
對於頻率直方圖,如果NDV小於254的情況,ndv應該是和桶數相等的.有些bug會產生不一致,導致評估不準確,具體可以參考metalink的相關bug。SQL> select count(b.endpoint_value) from user_histograms b where table_name=‘T1‘ and column_name=‘A‘;COUNT(B.ENDPOINT_VALUE)----------------------- 3SQL> select table_name,column_name,num_distinct from user_tab_col_statistics where table_name=‘T1‘ and column_name=‘A‘;TABLE_NAME COLUMN_NAME NUM_DISTINCT------------------------------ ------------------------------ ------------T2 A 3一般建議的收集方法為‘FOR ALL COLUMNS SIZE AUTO‘,除非有很好的理由去更改,由oracle自行決定是否需要histogram和桶數

ORACLE直方圖(10g)