一、什么是統計信息
統計信息主要是描述數據庫中表,索引的大小,規模,數據分布狀況等的一類信息。例如,表的行數,塊數,平均每行的大小,索引的leaf blocks,索引字段的行數,不同值的大小等,都屬於統計信息。CBO正是根據這些統計信息數據,計算出不同訪問路徑下,不同join 方式下,各種計划的成本,最后選擇出成本最小的計划。
統計信息是存放在數據字典表中的,如tab$,一般可通過察看某些視圖來獲取統計信息狀況,如DBA_TABLES,DBA_INDEXES,DBA_TAB_COL_STATISTICS, DBA_TAB_HISTOGRAMS等。在這些視圖中包含表示統計信息的一些字段,這些字段只有搜集過統計信息之后才有值,否則是空的。例如,last_analyzed 字段表示上次統計信息搜集的時間,可以根據這個字段,快速的了解最近一次統計信息搜集的時間。
二、收集統計信息的方法
- 使用gather_stats_job自動收集是在創建數據庫時自動創建的,並由調度程序進行管理。他會收集數據庫中優化程序統計信息缺失或已過時的所有對象的統計信息。
- 使用dbms_stats 程序包手動收集收集的是系統統計信息。
- 通過設置數據庫初始化參數進行收集。
- 通過從另一個數據庫導入統計信息進行收集。
三、Oracle自動收集統計信息的原理
統計信息對於Oracle數據庫來說至關重要,尤其是在使用CBO(基於成本的優化器)模式的時候,統計信息包括表的使用塊數、空閑塊數、平均行長度、統計信息收集時間等。在Oracle9i數據庫中,兩種優化器模式RBO和CBO並存,在默認情況下,optimizer_mode參數的值是choose,choose不是優化器模式,它表示在分析數據庫中的語句時,如果在對象上有統計信息,就是用CBO方式生成執行計划,如果對象上沒有統計信息,是使用RBO模式。
從總體上來說,CB的准確度高於RBO,但是它要求要有統計信息和統計信息必須准確,否則Oracle可能會做出錯誤的判斷。所以在Oracle9i數據庫中,我們會自己來規划在什么樣的時間采用什么樣的策略來收集統計信息。也就是說,Oracle9i的統計信息收集工作必須通過手工方式來實現。
到了Oracle10g,默認情況下,optimizer_mode=all_rows,也就是采用了CBO的方式,為了保證執行計划的准確,在周一到周五(晚22:00-次日6:00),通過一個job(gather_stat_job)自動收集對象的統計信息。這種自動收集統計信息的方式並不是收集所有對象的統計信息,而是收集沒有統計信息的對象和統計信息過舊的對象。
Automatic Statistics Gathering是由Scheduler調度GATHER_STATS_JOB作業來完成的,在GATHER_STATS_JOB作業中則調用DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC存儲過程。GATHER_DATABASE_STATS_JOB_PROC是一個內部的存儲過程,基本上跟DBMS_STATS.GATHER_DATABASE_STATS的功能一樣,但在其內部有優先順序的考慮,更新量(變化量)越多的表將會越優先收集統計信息。為對象收集統計信息的條件是,之前從來沒有收集過的或者是更新的(包括insert,update,delete,truncate)記錄數超過當前總記錄數10%的表(在Oracle11g中則提供了SET_TABLE_PREFS函數修改10%這個閾值)。記錄數的更改量由Oracle數據庫自動監控,在初始化參數statistics_level設置為TYPICAL或者ALL時,自動監控即會生效。
3.1 調整當更新量達(變化量)達到多少時開始統計信息收集任務
1
2
3
4
|
BEGIN
DBMS_STATS.SET_TABLE_PREFS ( ownname =>
'XXXXX'
, tabname =>
'T1'
, pname =>
'STALE_PERCENT'
, pvalue =>
'5'
);
END;
/
|
3.2 調整自動收集統計信息的執行時間
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
select
t1.window_name,t1.repeat_interval,t1.duration
from
dba_scheduler_windows t1,dba_scheduler_wingroup_members t2
where
t1.window_name=t2.window_name and t2.window_group_name
in
(
'MAINTENANCE_WINDOW_GROUP'
,
'BSLN_MAINTAIN_STATS_SCHED'
);
WINDOW_NAME REPEAT_INTERVAL DURATION
------------------------------ ------------------------------------------------------------ --------------------
MONDAY_WINDOW freq=daily;byday=MON;byhour=22;byminute=0; bysecond=0 +000 04:00:00
TUESDAY_WINDOW freq=daily;byday=TUE;byhour=22;byminute=0; bysecond=0 +000 04:00:00
WEDNESDAY_WINDOW freq=daily;byday=WED;byhour=22;byminute=0; bysecond=0 +000 04:00:00
THURSDAY_WINDOW freq=daily;byday=THU;byhour=22;byminute=0; bysecond=0 +000 04:00:00
FRIDAY_WINDOW freq=daily;byday=FRI;byhour=22;byminute=0; bysecond=0 +000 04:00:00
SATURDAY_WINDOW freq=daily;byday=SAT;byhour=6;byminute=0; bysecond=0 +000 20:00:00
SUNDAY_WINDOW freq=daily;byday=SUN;byhour=6;byminute=0; bysecond=0 +000 20:00:00
# WINDOW_NAME:任務名
# REPEAT_INTERVAL:任務重復間隔時間
# DURATION:持續時間
# 1.停止任務
BEGIN
DBMS_SCHEDULER.DISABLE(
name=>
'"SYS"."FRIDAY_WINDOW"'
,
force=>TRUE);
END;
# 2.修改任務的持續時間,單位是分鍾
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE(
name=>
'"SYS"."FRIDAY_WINDOW"'
,
attribute=>
'DURATION'
,
value=>numtodsinterval(180,
'minute'
));
END;
# 3.開始執行時間,BYHOUR=2,表示2點開始執行
BEGIN
DBMS_SCHEDULER.SET_ATTRIBUTE(
name=>
'"SYS"."FRIDAY_WINDOW"'
,
attribute=>
'REPEAT_INTERVAL'
,
value=>
'FREQ=WEEKLY;BYDAY=MON;BYHOUR=2;BYMINUTE=0;BYSECOND=0'
);
END;
# 4.開啟任務
BEGIN
DBMS_SCHEDULER.ENABLE(
name=>
'"SYS"."FRIDAY_WINDOW"'
);
END;
|
3.3 禁用統計信息自動收集
1
2
3
4
|
BEGIN
DBMS_SCHEDULER.DISABLE(
'GATHER_STATS_JOB'
);
END;
/
|
四、DBMS_STATS包
DBMS_STATS包,主要提供了搜集(gather),刪除(delete),導出(export),導入(import),修改(set)統計信息的方法。
dbms_stats與analyze的區別:
dbms_stats是Oracle9i及后續版本中用於收集統計信息的包,雖然analyze命令也一直可以使用,但是現在已經不推薦使用analyze命令來收集統計信息,而是使用dbms_stats。兩者之間有很大的不同,dbms_stats能正確收集分區表的統計信息,也就是說能夠收集global statistic,而analyze只能收集最低層次對象的統計信息,然后推導和匯總出高一級對象的統計信息,如果分區表只會收集分區統計信息,然后再匯總出所有分區的統計信息,得到表一級的統計信息。
4.1 什么是golbal statistic
golbal statistic是指直接從對象本身收集到的統計信息,而不是從下一級對象“推導”和“匯總”出來的統計信息,golbal statistic對於優化器來說非常重要,一個SQL,除非其查詢條件限制了數據只在分區上,否則大多數情況下需要golbal statistic才能得到正確的執行計划。有的統計值可以從下一級對象進行匯總后得到,如表的總行數,可以通過各分區的行數相加得到。但有的統計值不能通過下一級對象得到,比如列上的唯一值數量(distinct value)以及密度值(density)。
4.2 使用DBMS_STATS.GATHER_DATABASE_STATS收集整個數據庫的統計信息
1
2
3
4
5
6
7
|
BEGIN
dbms_stats.gather_database_stats(estimate_percent => dbms_stats.AUTO_SAMPLE_SIZE,
method_opt =>
'for all indexed columns'
,
options =>
'GATHER AUTO'
,
cascade => TRUE);
END;
/
|
參數說明:
1.estimate_percent:采樣的百分比,使用dbms_stats.auto_sample_size選項允許Oracle自動估算要采樣的一個segment的最佳百分比。
2.method_opt選項適合在表和索引數據發生變化時刷新統計數據:
- for table:只統計表
- for all indexed columns:只統計有索引的表列
- for all indexes:只分析統計相關索引
- for all columns:分析所有的列
dbms_stats的method_opt參數尤其適合在表和索引數據發生變化時刷新統計數據。method_opt參數也適合用於判斷哪些列需要直方圖(histograms)。某些情況下,索引內的各個值的分布會影響CBO是使用一個索引還是執行一次全表掃描的決策。例如,假如在where子句中指定的值的數量不對稱,全表掃描就顯得比索引訪問更經濟。
如果有一個高度傾斜的索引(某些值的行數不對稱),就可創建Oracle直方圖統計。但在現實世界中,出現這種情況的機率相當小。使用CBO時,最常見的錯誤之一就是在CBO統計中不必要地引入直方圖。為了智能地生成直方圖,Oracle為dbms_stats准備了method_opt參數。在method_opt子句中,還有一些重要的選項,包括skewonly,repeat和auto:
- method_opt=>'for all columns size skewonly'
- method_opt=>'for all columns size repeat'
- method_opt=>'for all columns size auto'
(1).skewonly選項會耗費大量處理時間,因為它要檢查每個索引中的每個列的值的分布情況。如果dbms_stat發現一個索引的各個列分布得不均勻,那么就會為該索引創建直方圖,幫助基於成本的SQL優化器決定是進行索引訪問,還是進行全表掃描訪問。
(2).repeat選項在重新分析任務所消耗的資源就會少一些。使用repeat選項時,只會為現有的直方圖重新分析索引,不再搜索其他直方圖機會。定期重新分析統計數據時,應該采取這種方式。
(3).auto選項根據數據分布以及應用程序訪問列的方式來創建直方圖。
3.options控制Oracle統計信息的刷新方式:
- gather:重新分析整個架構
- gather empty:只分析目前還沒有統計的表
- gather stale:只重新分析修改量超過10%的表(包括插入、更新和刪除)
- gather auto:重新分析當前沒有統計的對象,以及統計數據過期(變臟)的對象。使用gather auto類似於組合使用gather stale和gather empty
4.3 使用DBMS_STATS.GATHER_SCHEMA_STATS收集整個用戶下對象的統計信息
1
2
3
4
5
6
7
|
exec dbms_stats.gather_schema_stats(
ownname =>
'SCOTT'
,
options =>
'GATHER AUTO'
,
estimate_percent => dbms_stats.auto_sample_size,
method_opt =>
'for all columns size repeat'
,
degree =>15
)
|
4.4 使用DBMS_STATS.GATHER_TABLE_STATS收集表、列、索引的統計信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
dbms_stats.gather_table_stats(
owner VARCHAR2,
tablename VARCHAR2,
partname VARCHAR2,
estimate_percent NUMBER,
block_sample BOOLEAN,
method_opt VARCHAR2,
degree NUMBER,
granularity VARCHAR2,
cascade BOOLEAN,
stattab VARCHAR2,
statid VARCHAR2,
statown VARCHAR2,
no_invalidate BOOLEAN,
force BOOLEAN
)
|
參數說明:
1.owner:要分析表的所有者
2.tablename:要分析的表的表名
3.partname:分區名
4.estimate_percent:采樣行的百分比,從0.000001-100,null為全部分析,不采樣。常量DBMS_STATS.AUTO_SAMPLE_SIZE是默認值,由Oracle決定最佳采樣率。
5.block_sample:是否用塊采樣代替行采樣。
6.method_opt:決定histograms信息是怎樣被統計的,method_opt的取值如下:
- for all columns:統計所有的histograms
- for all indexed columns:統計所有index列的histograms
- for all hidden coloumns:統計hidden列的histograms
- for columns <list> SIZE <N> | REPEAT | AUTO | SKEWONLY 統計指定列的histograms,N的取值范圍是0-254
7.degree:設置統計信息收集的並行度,默認值為null。
8.cascade:收集索引的統計信息,默認為false
9.stattab:指定存儲統計信息的表。
10.statid:如果多個表的統計信息存儲在一個stattab中時,statid用作分區條件。
11.statown:存儲統計信息表的所有着。
如果不指定上述三個參數,則統計信息會被更新到數據字典。
12.force:即使表鎖住了也收集統計信息。
4.5 統計信息的導出導入刪除操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
# 1.創建統計信息歷史保留表
exec
dbms_stats.create_stat_table(
ownname =>
''
,
stattab =>
''
)
# 2.導出整個scheme的統計信息
exec
dbms_stats.export_schema_stats(
ownname =>
''
,
stattab =>
''
)
# 3.分析scheme
Exec
dbms_stats.gather_schema_stats(
ownname =>
''
,
options =>
'GATHER AUTO'
,
estimate_percent => dbms_stats.auto_sample_size,
method_opt =>
'for all indexed columns '
,
degree => 6
)
# 4.分析表
exec
dbms_stats.gather_table_stats(
ownname =>
''
,
tabname =>
''
,
estimate_percent => 10,
method_opt=>
'for all indexed columns'
)
# 5.分析索引
exec
dbms_stats.gather_index_stats(
ownname =>
''
,
indname =>
''
,
estimate_percent => 10,
degree => 6
)
# 6.如果發現執行計划走錯,刪除表的統計信息
exec
dbms_stats.delete_table_stats(
ownname =>
''
,
tabname =>
''
)
# 7.導入表的歷史統計信息
exec
dbms_stats.import_table_stats(
ownname =>
''
,
tabname =>
''
,
stattab =>
''
)
|
4.6 鎖住統計信息
將一個表的統計信息鎖住,以防止錯誤的統計信息將此正確的信息覆蓋掉時需要用到LOCK_TABLE_STATS包:
1
2
3
4
|
DBMS_STATS.LOCK_TABLE_STATS(
ownname VARCHAR2,
tabname VARCHAR2
);
|
參考文檔:
http://blog.csdn.net/outget1/article/details/4834000
統計信息主要是描述數據庫中表,索引的大小,規模,數據分布狀況等的一類信息。比如,表的行數,塊數,平均每行的大小,索引的leaf blocks,索引字段的行數,不同值的大小等,都屬於統計信息。CBO正是根據這些統計信息數據,計算出不同訪問路徑下,不同join 方式下,各種計划的成本,最后選擇出成本最小的計划。
在CBO(基於代價的優化器模式)條件下,SQL語句的執行計划由統計信息來決定,若沒有統計信息則會采取動態采樣的方式決定執行計划!可以說統計信息關乎sql的執行計划是否正確,屬於sql執行的指導思想,oracle的初始化參數statistics_level控制收集統計信息的級別,有三個參數值:
BASIC :收集基本的統計信息
TYPICAL:收集大部分統計信息(數據庫的默認設置)
ALL:收集全部統計信息
Oracle 10g之后,Query Optimizer就已經將CBO作為默認優化器,並且Oracle官方不再支持RBO服務。但是,通過優化器參數optimizer_mode,我們可以控制Oracle優化器生成不同模式下的執行計划。
關於優化器的請參考:《SQL性能優化之optimizer_mode參數原理滲透解析》
2.如何收集統計信息
2.1 統計信息的內容:
1)Table statistics
Number of rows --行數量
Number of blocks --block數量
Average row length --平均行的長度.
2)Column statistics
Number of distinct values (NDV) in column --列中distinct的值
Number of nulls in column --列中null的值
Data distribution (histogram) --數據分布
3)Index statistics
Number of leaf blocks --子節點的塊數量
Levels --子節點數量
Clustering factor --集群因子
4)System statistics
I/O performance and utilization --IO性能和利用率
CPU performance and utilization --CPU的性能和利用率
2.2 收集統計信息
Oracle Statistic 的收集,可以使用analyze 命令,也可以使用DBMS_STATS 包來收集,Oracle 建議使用DBMS_STATS包來收集統計信息,因為DBMS_STATS包收集的更廣,並且更准確。analyze 在以后的版本中可能會被移除。
DBMS_STATS常用的幾個過程如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
dbms_stats.gather_table_stats 收集表、列和索引的統計信息;
dbms_stats.gather_schema_stats 收集SCHEMA下所有對象的統計信息;
dbms_stats.gather_index_stats 收集索引的統計信息;
dbms_stats.gather_system_stats 收集系統統計信息
dbms_stats.GATHER_DICTIONARY_STATS:所有字典對象的統計;
DBMS_STATS.GATHER_DICTIONARY_STATS 其收集所有系統模式的統計
dbms_stats.delete_table_stats 刪除表的統計信息
dbms_stats.delete_index_stats 刪除索引的統計信息
dbms_stats.export_table_stats 輸出表的統計信息
dbms_stats.create_state_table
dbms_stats.set_table_stats 設置表的統計
dbms_stats.auto_sample_size
|
analyze 命令的語法如下:
1
2
3
|
SQL>analyze
table
tablename compute
statistics
;
SQL>analyze
table
tablename compute
statistics
for
all
indexes;
SQL>analyze
table
tablename
delete
statistics
|
2.3 統計信息的分類
Oracle 的Statistic 信息的收集分兩種:自動收集和手工收集。
Oracle 的Automatic Statistics Gathering 是通過Scheduler 來實現收集和維護的。Job 名稱是GATHER_STATS_JOB, 該Job收集數據庫所有對象的2種統計信息:
(1)Missing statistics(統計信息缺失)
(2)Stale statistics(統計信息陳舊)
該Job 是在數據庫創建的時候自動創建,並由Scheduler來管理。Scheduler 在maintenance windows open時運行gather job。 默認情況下,job 會在每天晚上10到早上6點和周末全天開啟。該過程首先檢測統計信息缺失和陳舊的對象。然后確定優先級,再開始進行統計信息。
Scheduler Job的stop_on_window_close 屬性控制GATHER_STATS_JOB 是否繼續。該屬性默認值為True. 如果該值設置為False,那么GATHER_STATS_JOB 會中斷, 而沒有收集完的對象將在下次啟動時繼續收集。
Gather_stats_job 調用dbms_stats.gather_database_stats_job_proc過程來收集statistics 的信息。 該過程收集對象statistics的條件如下:
(1)對象的統計信息之前沒有收集過。
(2)當對象有超過10%的rows 被修改,此時對象的統計信息也稱為stale statistics。
但是對於高度變化的表在白天的活動期間被TRUNCATE/DROP並重建或者塊加載超過本身總大小10%的對象;我們可以將這些表上的統計設置為NULL
可以通過以下SQL來查看:
1
2
3
|
select
job_name, program_name, enabled, stop_on_window_close
from
dba_scheduler_jobs
where
job_name =
'gather_stats_job'
;
|
為了決定是否對對象進行監控,Oracle 提供了一個參數STATISTICS_LEVEL。通過設置初始化參數STATISTIC_LEVEL 為TYPICAL 或ALL,就可以自動收集統計信息(默認值為TYPICAL,因此可以隨即啟用自動收集統計信息的功能)。STATISTIC_LEVEL 參數的值可以激活GATHER_STATS_JOB。
在10g中表監控默認是激活的,如果STATISTICS_LEVEL設置為basic,不僅不能監控表,而且將禁掉如下一些10g的新功能:
(1)ASH(Active Session History)
(2)ASSM(Automatic Shared Memory Management)
(3)AWR(Automatic Workload Repository)
(4)ADDM(Automatic Database Diagnostic Monitor)
1
2
3
4
5
|
sys@ORCL> show parameter statistics_level;
NAME
TYPE VALUE
------------------------------------ ----------- ---------
statistics_level string TYPICAL
|
當啟動對象的監控后,從上次統計信息收集之后的的信息,如inserts,updates,deletes 等,這些改變的信息會記錄到user_tab_modifications 視圖。
當對象的數據發生改變之后, 經過幾分鍾的延時,這些信息寫入到user_tab_modifications視圖,然后dbms_stats.flush_database_monitoring_info過程就會發現這些信息,並講這些信息保存在內存中。
當監控的對象被修改的部分超過10%時,gather_database_stats 或者gather_schema_stats 過程就會去收集這些stale statistics
3.統計信息的存儲位置以及常用數據字典
3.1 統計信息常用數據字典
統計信息收集如下數據:
(1)表自身的分析: 包括表中的行數,數據塊數,行長等信息。
(2)列的分析:包括列值的重復數,列上的空值,數據在列上的分布情況。
(3)索引的分析: 包括索引葉塊的數量,索引的深度,索引的聚合因子等。
這些統計信息存放在以下的數據字典里:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
DBA_TABLES
DBA_OBJECT_TABLES
DBA_TAB_STATISTICS
DBA_TAB_COL_STATISTICS
DBA_TAB_HISTOGRAMS
DBA_INDEXES
DBA_IND_STATISTICS
DBA_CLUSTERS
DBA_TAB_PARTITIONS
DBA_TAB_SUBPARTITIONS
DBA_IND_PARTITIONS
DBA_IND_SUBPARTITIONS
DBA_PART_COL_STATISTICS
DBA_PART_HISTOGRAMS
DBA_SUBPART_COL_STATISTICS
DBA_SUBPART_HISTOGRAMS
|
3.2 表的統計信息
包含表行數,使用的塊數,空的塊數,塊的使用率,行遷移和鏈接的數量,pctfree,pctused的數據,行的平均大小:
1
2
3
4
5
6
7
|
SELECT
NUM_ROWS,
--表中的記錄數
BLOCKS,
--表中數據所占的數據塊數
EMPTY_BLOCKS,
--表中的空塊數
AVG_SPACE,
--數據塊中平均的使用空間
CHAIN_CNT,
--表中行連接和行遷移的數量
AVG_ROW_LEN
--每條記錄的平均長度
FROM
USER_TABLES
|
3.3索引列的統計信息
包含索引的深度(B-Tree的級別),索引葉級的塊數量,集群因子(clustering_factor), 唯一值的個數。
1
2
3
4
5
6
7
|
SELECT
BLEVEL,
--索引的層數
LEAF_BLOCKS,
--葉子結點的個數
DISTINCT_KEYS,
--唯一值的個數
AVG_LEAF_BLOCKS_PER_KEY,
--每個KEY的平均葉塊個數
AVG_DATA_BLOCKS_PER_KEY,
--每個KEY的平均數據塊個數
CLUSTERING_FACTOR
--群集因子
FROM
USER_INDEXES
|
3.4 列的統計信息
包含唯一的值個數,列最大小值,密度(選擇率),數據分布(直方圖信息),NUll值個數
1
2
3
4
5
6
7
8
|
SELECT
NUM_DISTINCT,
--唯一值的個數
LOW_VALUE,
--列上的最小值
HIGH_VALUE,
--列上的最大值
DENSITY,
--選擇率因子(密度)
NUM_NULLS,
--空值的個數
NUM_BUCKETS,
--直方圖的BUCKET個數
HISTOGRAM
--直方圖的類型
FROM
USER_TAB_COLUMNS
|