一、什麼是統計信息?sql
統計信息就是數據庫的偵察兵,記錄了表和表中一些列的一些信息,通常SQL指定執行計劃的時候都要先看錶的統計信息,以決定執行計劃的選擇。數據庫
表的統計信息通常在dba_tables中,表中列的統計信息通常在dba_tab_col_statisticssession
select table_name,column_name,num_distinct,num_nulls,last_analyzed,avg_col_len,histogram from dba_tab_col_statistics where table_name='TEST';oracle
沒有收集統計系信息以前,dba_tables中記錄的關於表的 num_rows和blocks都是空的。 dba_tab_col_statistics中是沒有列的記錄的。咱們來看一下手機完統計信息的狀態。ui
select table_name,column_name,num_distinct,num_nulls,last_analyzed,avg_col_len,histogram from dba_tab_col_statistics where table_name='TEST';spa
收集統計信息的過程:code
一、將表有多少行,表中有多少個block 計算出來,記錄到dba_tables中。(select count(*) from test; select SEGMENT_NAME,blocks from dba_segments where segment_name='TEST'; )orm
二、計算表中每一個列的基數,null值,平均的行長度等,記錄到基表中。blog
採樣率:索引
一個表是由塊組成的,若是採樣率不是100%有些塊就會收集不到。若是採樣率設置成30%,就會隨機的抽取表中30%的塊,進行統計信息的收集。
小表基本都是100%收集的。
通常經驗: <1G 100% 1-5G 50% 5-10G 30% >10G通常爲分區表了,老分區的數據通常是不會變的, 最新一個區的數據纔會變化,因此通常是已分區爲粒度來收集的。
(estimate_persent => 100)控制,若是不指定採樣比,oracle會自動選擇採樣率,也是默認的選項,最後使用默認。
收集直方圖與否:
method_opt => for all columns size 1 不收集直方圖
method_opt => for all columns size skewonly 收集直方圖 (沒收集直方圖以前histogram是none,num_bucket是0)
自動收集直方圖時,Oracle對直方圖的選擇, FREQUENCY ----頻率直方圖(基數小於254時使用) HEIGHT BALANCED ------ 等高直方圖(基數大於254時使用) NONE distinct值=行數 或者distinct值爲0的時候不收集
生產中不能夠使用這個選項,由於表咱們只對where中的列和基數很低的列收集。。這個選項會收集全部列的
method_opt => for all columns size auto 這個是10g、11g、12c中收集統計信息的默認選項,自動根據where條件中的信息對列有選擇性的收直方圖(只收集出如今where條件中而且基數很低的列)。也是官方推薦的方式
Oracle怎麼判斷哪些列在where條件中呢? begin dbms_stats.flush_database_monitoring_info;end;--將內存中的統計數據刷出去【這個在生產上也能夠隨便刷,就是將內存中的數據刷到磁盤上,這個數據很是小,不會刷死庫的】 (默認是由smon刷的,15min一次) select r.name owner, o.name table_name, c.name column_name, equality_preds,----等值過濾的次數 equijoin_preds,----等值過濾join,好比where a.id=b.in range_preds,----範圍過濾,好比><and,between like_preds,----like過濾 null_preds,----null過濾 timestamp from sys.col_usage$ u,sys.obj$ o,sys.col$ c,sys.user$ r where o.obj# = u.obj# and c.obj# = u.obj# and c.col# = u.intcol# and r.name = 'SCOTT' and o.name = 'TEST';
auto也不是萬能的,好比 有些時候生產上的where條件是沒有某些列的,可是咱們私底下sqlplus查詢時候查過這些列,也會致使這些列被auto收集。
method_opt => for all columns size repeat 延續上一次收集的方法,以前怎麼收集的,此次還怎麼收集
method_opt => for columns owner size auto 只針對owner列收集直方圖 (下次若是是for all columns size repeat 仍是隻對owner收集直方圖)
method_opt = > for columns owner,subobject_name size auto 對owner和subobject_name兩列收集直方圖(若是肯定了哪些列要收集直方圖,之後每次收集的時候都肯定也能夠不用repeat)
通常去新公司工做的時候用repeat (其實11g後用auto也能夠)
新系統上線的時候用 1,不收集直方圖,對跑得慢的列再收直方圖,長此以往這個系統就穩定了
統計信息知識總結:
一、如何查看已收集了統計信息的一個表的採樣率:
select owner,table_name,num_rows,sample_size, ceil(sample_size/num_rows*100) estimate_percent from dba_tab_statistics where owner = 'SCOTT' and table_name = 'TEST';
二、收集統計信息:
begin dbms_stats.gather_table_stats( ownname=>'SCOTT', tabname=>'TEST', estimate_percent=>30, method_opt=>'for all columns size auto', no_invalidate=>FALSE, degree=>1, cascade=>true); end; /
三、收集完統計信息後,隔多久再收集一次?
3.1看統計信息是否過時。過時就須要收集。
判斷統計信息是否過時:
begin dbms_stats.flush_database_monitoring_info; end; / select owner,table_name name,object_type,stale_stats, last_analyzed from dba_tab_statistics where table_name in ('TEST') and owner = 'SCOTT' and (stale_stats = 'YES' or last_analyzed is null);
stale_stats爲 no 就是沒有過時,yes 就是過時了。
一個表有超過10%的數據變化,統計信息就會過時
3.2 怎麼判斷統計信息是由於什麼過時的。
alter session set nls_date_format='yyyymmdd hh24:mi:ss';
col owner for a15 col table_name for a15 col partition_name for a20 col subpartition_name for a20 select * from ( select * from ( select * from ( select u.name owner,o.name table_name, null partition_name, null subpartition_name, m.inserts,m.updates,m.deletes,m.timestamp, decode(bitand(m.flags,1),1,'YES','NO') truncated, m.drop_segments from sys.mon_mods_all$ m, sys.obj$ o,sys.tab$ t,sys.user$ u where o.obj# = m.obj# and o.obj#=t.obj# and o.owner# = u.user# union all select u.name,o.name,o.subname,null, m.inserts,m.updates,m.deletes,m.timestamp, decode(bitand(m.flags,1),1,'YES','NO'), m.drop_segments from sys.mon_mods_all$ m,sys.obj$ o,sys.user$ u where o.owner#=u.user# and o.obj#=m.obj# and o.type#=19 union all select u.name,o.name,o2.subname,o.subname, m.inserts,m.updates,m.deletes,m.timestamp, decode(bitand(m.flags,1),1,'YES','NO'), m.drop_segments from sys.mon_mods_all$ m,sys.obj$ o,sys.tabsubpart$ tsp,sys.obj$ o2, sys.user$ u where o.obj#=m.obj# and o.owner#=u.user# and o.obj# = tsp.obj# and o2.obj#=tsp.pobj# ) where owner not like '%SYS%' and owner not like 'XDB' union all select * from ( select u.name owner,o.name table_name,null partition_name, null subpartition_name, m.inserts,m.updates,m.deletes,m.timestamp, decode(bitand(m.flags,1),1,'YES','NO') truncated, m.drop_segments from sys.mon_mods$ m,sys.obj$ o,sys.tab$ t,sys.user$ u where o.obj#=m.obj# and o.obj#=t.obj# and o.owner#=u.user# union all select u.name,o.name,o.subname,null, m.inserts,m.updates,m.deletes,m.timestamp, decode(bitand(m.flags,1),1,'YES','NO'), m.drop_segments from sys.mon_mods$ m,sys.obj$ o,sys.user$ u where o.owner#=u.user# and o.obj#=m.obj# and o.type#=19 union all select u.name,o.name,o2.subname,o.subname, m.inserts,m.updates,m.deletes,m.timestamp, decode(bitand(m.flags,1),1,'YES','NO'), m.drop_segments from sys.mon_mods$ m,sys.obj$ o,sys.tabsubpart$ tsp,sys.obj$ o2, sys.user$ u where o.obj#=m.obj# and o.owner#=u.user# and o.obj# = tsp.obj# and o2.obj#=tsp.pobj# ) where owner not like '%SYS%' and owner not like '%XDB%' ) order by inserts desc ) where rownum<50;
該語句查詢的是 最近一次收集統計信息後,到如今爲止表數據量的變化。
該腳本能夠用來監控系統中核心表的dml,也能夠判斷高水位線是否須要回收、索引是否須要重建,等等。
3.3 數據庫有一個自動的job天天晚上自動收集統計信息。
AUTOTASK只收集變化量超過10%的表
若是有但願的計劃任務,最好用OS的crontab不要用scheduler,scheduler會死,可是crontab不會
數據庫自帶的job收集統計信息是很差的,由於頗有可能收集不完。
最好把db自帶的收集統計信息的job停掉,而後本身定製收集方案。