一、什么是統計信息
統計信息主要是描述數據庫中表,索引的大小,規模,數據分布狀況等的一類信息。例如,表的行數,塊數,平均每行的大小,索引的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 調整當更新量達(變化量)達到多少時開始統計信息收集任務
BEGIN DBMS_STATS.SET_TABLE_PREFS ( ownname =>'XXXXX', tabname =>'T1', pname =>'STALE_PERCENT', pvalue =>'5'); END; /
3.2 調整自動收集統計信息的執行時間
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 禁用統計信息自動收集
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收集整個數據庫的統計信息
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收集整個用戶下對象的統計信息
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收集表、列、索引的統計信息
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.創建統計信息歷史保留表 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包:
DBMS_STATS.LOCK_TABLE_STATS( ownname VARCHAR2, tabname VARCHAR2 );
參考文檔:
http://blog.csdn.net/outget1/article/details/4834000