Oracle 字段監控 ( column monitor)
Table of Contents
從oracle9i開始,oracle為了監控column的使用情況,引入了col_usage$ 基表,該表會記錄 數據庫運行期間column作為謂詞被使用的情況,這些記錄信息會指導oracle如何生成column的 直方圖。
這是Oracle 本身原本的意圖,從另外一個角度上來講,我們可以以此為依據,判斷哪個字段上 應該建立索引。
1 開啟與關閉
Oracle通過隱藏參數"_column_tracking_level"控制此功能的開關:
- 0
- 禁用column tracking
- 1
- 啟用column tracking
此參數可以在session 或者system級別動態調整,不需要重新啟動數據庫。
2 字段說明
表字段可以通過desc col_usage$來查看。如:
sql> desc col_usage$
字段 | 含義 |
---|---|
OBJ# | DBA_OBJECTS.OBJECT_ID |
INTCOL# | |
EQUALITY_PREDS | 等值查詢 |
EQUIJOIN_PREDS | 等值連接 |
NONEQUIJOIN_PREDS | 不等值連接 |
RANGE_PREDS | 范圍查詢 |
LIKE_PREDS | 使用LIKE關鍵字查詢 |
NULL_PREDS | 空值查詢 |
TIMESTAMP | 時間戳 |
3 數據來源與清除
- 插入
- 自動 SMON里程每15分鍾將SGA中的內容刷新到col_usage$表中
- 手動 調用DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO
- 清除 在數據庫實例關閉的時候,smon會清除無效的行,比如某張表被刪除,與此表相關的信息 即為無效。
4 對直方圖的影響
從Oracle 10G 開始,收集表統計信息時,若采用 ”FOR ALL COLUMNS SIZE AUTO" 的方式。如果某張表的字段存在於COL_USAGE$中,數據庫就會認為有必要收集直方圖信息。
5 對建立索引的影響
開啟此功能后,我們可以對字段被用於查詢條件的情況進行區分統計。哪個字段被使用到, 被使用的頻率有多高,是用於連接還是范圍查詢等等。這些信息,對於我們創建索引,創 建什么類型的索引,是一個重要的依據。
6 Col_Usage$
6.0.1 表結構
我們先來看看這張表的結構。
create table col_usage$ ( obj# number, /* object number */ intcol# number, /* internal column number */ equality_preds number, /* equality predicates */ equijoin_preds number, /* equijoin predicates */ nonequijoin_preds number, /* nonequijoin predicates */ range_preds number, /* range predicates */ like_preds number, /* (not) like predicates */ null_preds number, /* (not) null predicates */ timestamp date /* timestamp of last time this row was changed */ ) storage (initial 200K next 100k maxextents unlimited pctincrease 0) / create unique index i_col_usage$ on col_usage$(obj#,intcol#) storage (maxextents unlimited) /
6.0.2 COL_USAGE$字段說明
columen | related to |
---|---|
obj# | obj$.obj# |
intcol# | col$.col# |
obj# | 與基表obj$.obj# 相關聯 |
intcol# | 與基表col$.col# 相關聯 |
preds | 指的是predicate,也就是where條件語句中的條件。 |
equlity_preds | 賦值條件 |
equijoin_preds | 等值連接 |
nonequijoin_preds | 非等值連接 |
range_preds | 范圍查詢 |
like_preds | 模糊查詢 |
null_preds | 空值匹配查詢 |
timestamp | COL_USAGE$ 表中該行數據更新時間 |
6.0.3 refresh COL_USAGE$(刷新基表)
- refresh automatically(自動刷新)
字段訪問記錄被保存在SGA中,SMON 會每隔15分鍾將這些信息從內存中刷新至基表COL_USAGE$中。SMON進程會對該表進行插入、更新、刪除操作。當一個字段被首次訪問后,SMON在刷新內存信息時,會在表中插入一行新的數據,如果字段或者表被刪除,與其相關的字段信息會被SMON從COL_USAGE$中刪除。
- refresh manually(手動刷新)
REFRESH THE TABLE(刷新COL_USAGE$)
上面已經提及,SMON 進程會每隔15分鍾將SGA 中的字段訪問數據更新到COL_USAGE$表中。那么如果我們想得到最新的字段訪問數據,該怎么辦呢? Oracle 提供了一個包:DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO.
exec dbms_stats.flush_database_monitoring_info;
6.0.4 利用COL_USAGE$表
在收集表的統計信息時,依據此表決定是否對某個字段收集直方圖。我們是否可以利用它呢? 不知道你是否遇到過這種場景:
你負責對優化數據庫,其中一個很重要的工作就是創建索引,但是你對業務邏輯和數據庫都不 太了解,這時你會怎么做? 如何決定哪個字段應該創建索引?
這種時候,這張表可以給我們提供相應的信息,因為它里面存儲了所有字段的訪問記錄。
col table_owner heading "Tab Owner" for a9 col table_name heading "Table Name" for a30 col column_name heading "Col Name" for a20 col col_acc_num for 9999999 col indexed for a8 select u.name as table_owner, o.name as table_name, c.name as column_name, cu.equality_preds + cu.equijoin_preds + cu.nonequijoin_preds + cu.range_preds + cu.like_preds + cu.null_preds as col_acc_num, lpad(decode(ic.obj#, null, 'no', 'yes'),5,' ') as indexed, to_char(round(ratio_to_report(cu.equality_preds + cu.equijoin_preds + cu.nonequijoin_preds + cu.range_preds + cu.like_preds + cu.null_preds) over() * 100, 2),'fm990.00') pct from sys.col_usage$ cu, sys.obj$ o, (select distinct obj#, intcol#, name, property from sys.col$) c, sys.user$ u, sys.icol$ ic where cu.obj# = o.obj# and cu.intcol# = c.intcol# and o.obj# = c.obj# and o.owner# = u.user# and c.intcol# = ic.intcol#(+) and c.obj# = ic.bo#(+) and u.name not in( 'NONYMOUS','CTXSYS','DIP','DBSNMP','DMSYS','EXFSYS','MDDATA','MDSYS', 'MGMT_VIEW','OLAPSYS','ORDPLUGINS','ORDSYS','OUTLN','SCOTT','SI_INFORMTN', '_SCHEMA','SYS','SYSMAN','SYSTEM','WK_TEST','WKPROXY','WKSYS','WMSYS' ,'XDB','TSMSYS','ORACLE_OCM') and o.name not like 'BIN$%' order by 6 /
6.0.5 TEST(測試示例)
create table scott.t_halberd_colmon as select * from dba_objects; SELECT OBJECT_ID,OBJECT_NAME FROM DBA_OBJECTS WHERE OWNER='SCOTT' and object_type='TABLE'; EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO; select * from col_usage$ where obj#=98581; exec dbms_stats.gather_table_stats(ownname=>'SCOTT',TABNAME=>'T_HALBERD_COLMON',METHOD_OPT=>'FOR ALL COLUMNS SIZE AUTO'); SELECT table_name, column_name,histogram,num_distinct,num_buckets,sample_size,last_analyzed FROM DBA_TAB_COL_STATISTICS WHERE OWNER='SCOTT'; SELECT COUNT(*) FROM SCOTT.T_HALBERD_COLMON WHERE OBJECT_ID < 200; EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO; select * from col_usage$ where obj#=98581; SELECT table_name, column_name,histogram,num_distinct,num_buckets,sample_size,last_analyzed FROM DBA_TAB_COL_STATISTICS WHERE OWNER='SCOTT'; UPDATE SCOTT.T_HALBERD_COLMON SET OBJECT_ID = MOD(OBJECT_ID,25); EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO; select * from col_usage$ where obj#=98581; exec dbms_stats.gather_table_stats(ownname=>'SCOTT',TABNAME=>'T_HALBERD_COLMON',METHOD_OPT=>'FOR ALL COLUMNS SIZE AUTO'); SELECT table_name, column_name,histogram,num_distinct,num_buckets,sample_size,last_analyzed FROM DBA_TAB_COL_STATISTICS WHERE OWNER='SCOTT'; update scott.t1 set object_name=object_id; select count(*) from scott.t1 where object_name like '%4%'; EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO; select * from col_usage$ where obj#=98581; exec dbms_stats.gather_table_stats(ownname=>'SCOTT',TABNAME=>'T_HALBERD_COLMON',METHOD_OPT=>'FOR ALL COLUMNS SIZE AUTO'); SELECT table_name, column_name,histogram,num_distinct,num_buckets,sample_size,last_analyzed FROM DBA_TAB_COL_STATISTICS WHERE OWNER='SCOTT'; exec dbms_stats.delete_table_stats(ownname=>'SCOTT',TABNAME=>'T_HALBERD_COLMON'); SELECT table_name, column_name,histogram,num_distinct,num_buckets,sample_size,last_analyzed FROM DBA_TAB_COL_STATISTICS WHERE OWNER='SCOTT'; select * from col_usage$ where obj#=98581; delete from col_usage$ where obj#=98581 and intcol#=1; exec dbms_stats.gather_table_stats(ownname=>'SCOTT',TABNAME=>'T_HALBERD_COLMON',METHOD_OPT=>'FOR ALL COLUMNS SIZE AUTO'); SELECT table_name, column_name,histogram,num_distinct,num_buckets,sample_size,last_analyzed FROM DBA_TAB_COL_STATISTICS WHERE OWNER='SCOTT';
–如果在col_usgae$不存在對應記錄,在size auto模式下是不會生成直方圖的
Created: 2019-06-22 Sat 13:58