数据库优化之统计分析实战篇
生活随笔
收集整理的這篇文章主要介紹了
数据库优化之统计分析实战篇
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們發現有很多dba對
oracle
的統計分析都存在一些誤解,認為這個是oracle后臺自動運行的,我們不用去關心,我覺得統計分析有很深的學問。
我想問大家的是:
1、你們開啟了的每天收集統計信息,每天窗口運行正常嗎?
2、所有的表都使用oracle的自動窗口收集?大表是不是要考慮定制收集?分區表是不是要增量收集?
3、在不影響業務的情況下,什么時間段收集統計信息?
4、如何判斷統計信息是否過期,如何判斷哪些字段需要收集直方圖,收集的規則是什么?
下面我來一一解答:
1、
查詢自動任務是否開啟
SELECT OPERATION_NAME,STATUS FROM DBA_AUTOTASK_OPERATION WHERE CLIENT_NAME LIKE '%stats%';
STATUS為ENABLED表示任務開啟?
如果為DISABLE exec dbms_auto_task_admin.ENABLE(client_name => 'auto optimizer stats collection',operation =>'auto optimizer stats job',window_name=> null);?
查看后臺的窗口信息:
select * from dba_scheduler_windows
查看每天的統計JOB是否成功 racle 11g 調用窗口會自動生成以ORA$AT_OS_OPT開頭的JOB
select * from dba_scheduler_job_run_details where job_name LIKE '%ORA$AT_OS_OPT%' ORDER BY LOG_DATE DESC?
如果stoped要查看具體的內容:我這邊有兩次發生stop.
(1) 執行總共收集的時間,超出了收集窗口的時間(默認是周一到周五 22:00~02:00 4個小時 周六和周日06:00~02:00 20個小時)
? ? 解決辦法:可以開啟并行收集(默認是串行)
? ? EXEC DBMS_STATS.SET_PARAM('DEGREE',4);
? ? 或者將窗口時間調長
? ?begin
? ?dbms_scheduler.set_attribute(name => 'TUESDAY_WINDOW', attribute => 'duration', value =>numtdosinterval(480,'minute'));
? ?end;
? ?/
? ???
(2) job執行到一半的時候,由于其它窗口啟動導致收集終止。
? ? 解決辦法:將收集的窗口優先級調高?
? ? BEGIN
??dbms_scheduler.set_attribute(
? ? name? ?? ?=> 'TUESDAY_WINDOW',
? ? attribute => 'window_priority',
? ? value? ???=> 'HIGH');
? ?END;
? ?/
---備注:調整窗口的時間點收集:
BEGIN
??dbms_scheduler.disable(
? ? name??=> 'TUESDAY_WINDOW');
??dbms_scheduler.set_attribute(
? ? name? ?? ?=> 'TUESDAY_WINDOW',
? ? attribute => 'repeat_interval',
? ? value? ???=> 'freq=daily;byday=TUE;byhour=03;byminute=0;bysecond=0');
??dbms_scheduler.enable(
? ? name => 'TUESDAY_WINDOW');
END;
/
2、表是否都是oracle自動收集
(1) 獲取對象級別的統計信息設置選型
SELECT * FROM DBA_TAB_STAT_PREFS?
(2)大表我們要定制化收集,調整收集的采樣率(例如我們有張表是800G,如果你使用oracle的默認收集,收集時間保守估計在800分鐘)
??
??可以定制收集
??exec dbms_stats.set_table_prefs('用戶名','表名','STALE_PERCENT',100);
??
??BEGIN
? ?DBMS_STATS.GATHER_TABLE_STATS(ownname => 'XX',
? ?tabname => 'XX',
? ? estimate_percent => 30,
? ? degree => 4,
? ? no_invalidate? ? => FALSE,
? ? method_opt => 'for all columns size auto',
? ? cascade=>TRUE
? ?);
? ? END;??
具體什么樣的表需要定制,這個根據你們的數據庫實際情況,找出具體的表手工收集,下面有個腳本參考一下:
declare
??cursor stale_table is
??select owner, segment_name,
? ?? ?? ?case??when size_gb<0.5 then 30
? ?? ?? ?when size_gb>=0.5 and size_gb<1 then 20
? ?? ?? ?when size_gb >=1 and size_gb<5 then 10
? ?? ?? ?when size_gb>=5 and size_gb<10 then
? ?? ?? ?when size_gb>=10 then 1
? ?? ?? ?end as percent,
? ?? ?? ?8 as degree
? ?? ?? ? from (select owner,segment_name,sum(bytes/1024/1024/1024)size_gb
? ?? ?? ? from dba_segments where owner='' AND SEGMENT_NAME IN
? ?? ?? ? (SELECT /*+ UNNEST */ DISTINCT TABLE_NAME FROM DBA_TAB_STATISTICS WHERE
? ?? ?? ? (LAST_ANALYZED IS NULL OR STALE_STATS='YES') AND OWNER='')
? ?? ?? ? GROUP BY OWNER,SEGMENT_NAME);
? ?? ?? ? BEGIN
FOR STALE IN STALE_TABLE LOOP
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME =>STALE.OWNER,
??TABNAME=>STALE.SEGMENT_NAME,
??ESTIMATE_PERCENT =>STALE.PERCENT,
??METHOD_OPT =>'for all colums size skewonly',---默認oracle 是for all colums size auto
??degree =>8,
??granularity =>'ALL',
??cascade =>true);
??end 1oop;
??end;
(3) 分區表的增量收集:
exec dbms_stats.set_table_prefs('username','TABLENAME','INCREMENTAL','TRUE');
為什么要增量收集,我們這邊有一個log表,記錄用戶下的所有源表的增刪改查,這個表用于用戶程序的增量同步的判斷。
每天的數據量很大,按周的rang分區,查詢的時間都是在最近時間。
----我們暫且不用考慮分區表的設計問題和增量的斷點問題。
3、第三點上面已經解答。
4、
(1)判斷是否過期
(stale_stats='YES' or last_analyzed is??null)可以說明統計信息過期:
??select owner,table_name ,object_type,stale_stats,last_analyzed from dba_tab_statistics where owner ='XX'
and??table_name in('XX')??
(2)oracle默認表的變化量在10%收集統計信息。
有時我們發現有些表數據量變化不大,很久沒有收集統計信息,導致執行計劃問題(oracle 估算基數處在一個臨界點)我們可以根據表的變化率進行微調,從而制定合理的閥值。
查看表的變化率:
select *
??from (select t2.table_name,
? ?? ?? ?? ?? ?t2.partition_name,
? ?? ?? ?? ?? ?t2.subpartition_name,
? ?? ?? ?? ?? ?t2.inserts,
? ?? ?? ?? ?? ?t2.updates,
? ?? ?? ?? ?? ?t2.deletes,
? ?? ?? ?? ?? ?t1.NUM_ROWS,
? ?? ?? ?? ?? ?case
? ?? ?? ?? ?? ???when (t1.NUM_ROWS = 0 or t1.NUM_ROWS is null) then
? ?? ?? ?? ?? ?? ?100
? ?? ?? ?? ?? ???else
? ?? ?? ?? ?? ?? ?trunc((t2.inserts + t2.updates + t2.deletes) / t1.NUM_ROWS * 100,
? ?? ?? ?? ?? ?? ?? ?? ?2)
? ?? ?? ?? ?? ?end "mod_pct(%)",
? ?? ?? ?? ?? ?case
? ?? ?? ?? ?? ???when t1.LAST_ANALYZED is null then
? ?? ?? ?? ?? ?? ?'未分析'
? ?? ?? ?? ?? ???else
? ?? ?? ?? ?? ?? ?to_char(t1.LAST_ANALYZED)
? ?? ?? ?? ?? ?end LAST_ANALYZED,
? ?? ?? ?? ?? ? t2.timestamp,
? ?? ?? ?? ?? ?'begin dbms_stats.gather_table_stats('||'ownname=>'''|| t2.table_owner ||
? ?? ?? ?? ?? ?''','||'tabname=>''' || t2.table_name ||''','||'estimate_percent=>100'||','||'degree=>4'||',cascade => TRUE); end;' EXEC_STATS
? ?? ?? ? from dba_tab_statistics t1, dba_tab_modifications t2
? ?? ?? ?where t1.OWNER = t2.table_owner
? ?? ?? ???and t1.TABLE_NAME = t2.table_name
? ?? ?? ???and DECODE(t1.PARTITION_NAME, t2.partition_name, 0, 1) = 0
? ?? ?? ???and DECODE(t1.SUBPARTITION_NAME, t2.subpartition_name, 0, 1) = 0
? ?? ?? ???and t2.table_owner = '' AND T2.table_name='')
where "mod_pct(%)" >= 0
order by "mod_pct(%)" desc;
調整閥值:
? ?exec dbms_stats.set_table_prefs('用戶名','表名','STALE_PERCENT',1); 這樣表變化率在1%會自動收集
(3) 直方圖什么情況下收集:
oracle默認是for all colums size auto
??oracle文檔中說(文檔 ID 338926.1)中有描述
?? Oracle ?determines the columns to collect histograms based on data distribution and the workload of the columns.
??其實這句話有兩層含義?
??一是必須這個字段是被條件篩選到就是where a=xx
??select object_id from dba_objects where owner='XX' and object_name='XX';
??select name,intcol# from sys.col$ where obj#=XX and name='XX';
??select obj#,intcol#,equality_preds from sys.col_usage$ where obj#=XX;
??這個字段equality_preds要有值
??二是 字段的數據有傾斜
??select count(distinct a) from xx 和select count(*) from xx??數據量不能相等并且數據量大于254,會以HEIGHT BALANCED收集。
??小于254會以FREQUENCY方式收集,當然我們也可以指定桶的大小。
??
5 具體什么情況下用 auto 、repeat??和 skewonly 方式收集統計信息,這個要理解這三個參數的含義。我個人的見解
??auto 使用于系統上線的初期,系統上線穩定了使用repeat方式,如果要自己定制收集使用skewonly方式。
如果發現不足之處,望指出。
我想問大家的是:
1、你們開啟了的每天收集統計信息,每天窗口運行正常嗎?
2、所有的表都使用oracle的自動窗口收集?大表是不是要考慮定制收集?分區表是不是要增量收集?
3、在不影響業務的情況下,什么時間段收集統計信息?
4、如何判斷統計信息是否過期,如何判斷哪些字段需要收集直方圖,收集的規則是什么?
下面我來一一解答:
1、
查詢自動任務是否開啟
SELECT OPERATION_NAME,STATUS FROM DBA_AUTOTASK_OPERATION WHERE CLIENT_NAME LIKE '%stats%';
STATUS為ENABLED表示任務開啟?
如果為DISABLE exec dbms_auto_task_admin.ENABLE(client_name => 'auto optimizer stats collection',operation =>'auto optimizer stats job',window_name=> null);?
查看后臺的窗口信息:
select * from dba_scheduler_windows
查看每天的統計JOB是否成功 racle 11g 調用窗口會自動生成以ORA$AT_OS_OPT開頭的JOB
select * from dba_scheduler_job_run_details where job_name LIKE '%ORA$AT_OS_OPT%' ORDER BY LOG_DATE DESC?
如果stoped要查看具體的內容:我這邊有兩次發生stop.
(1) 執行總共收集的時間,超出了收集窗口的時間(默認是周一到周五 22:00~02:00 4個小時 周六和周日06:00~02:00 20個小時)
? ? 解決辦法:可以開啟并行收集(默認是串行)
? ? EXEC DBMS_STATS.SET_PARAM('DEGREE',4);
? ? 或者將窗口時間調長
? ?begin
? ?dbms_scheduler.set_attribute(name => 'TUESDAY_WINDOW', attribute => 'duration', value =>numtdosinterval(480,'minute'));
? ?end;
? ?/
? ???
(2) job執行到一半的時候,由于其它窗口啟動導致收集終止。
? ? 解決辦法:將收集的窗口優先級調高?
? ? BEGIN
??dbms_scheduler.set_attribute(
? ? name? ?? ?=> 'TUESDAY_WINDOW',
? ? attribute => 'window_priority',
? ? value? ???=> 'HIGH');
? ?END;
? ?/
---備注:調整窗口的時間點收集:
BEGIN
??dbms_scheduler.disable(
? ? name??=> 'TUESDAY_WINDOW');
??dbms_scheduler.set_attribute(
? ? name? ?? ?=> 'TUESDAY_WINDOW',
? ? attribute => 'repeat_interval',
? ? value? ???=> 'freq=daily;byday=TUE;byhour=03;byminute=0;bysecond=0');
??dbms_scheduler.enable(
? ? name => 'TUESDAY_WINDOW');
END;
/
2、表是否都是oracle自動收集
(1) 獲取對象級別的統計信息設置選型
SELECT * FROM DBA_TAB_STAT_PREFS?
(2)大表我們要定制化收集,調整收集的采樣率(例如我們有張表是800G,如果你使用oracle的默認收集,收集時間保守估計在800分鐘)
??
??可以定制收集
??exec dbms_stats.set_table_prefs('用戶名','表名','STALE_PERCENT',100);
??
??BEGIN
? ?DBMS_STATS.GATHER_TABLE_STATS(ownname => 'XX',
? ?tabname => 'XX',
? ? estimate_percent => 30,
? ? degree => 4,
? ? no_invalidate? ? => FALSE,
? ? method_opt => 'for all columns size auto',
? ? cascade=>TRUE
? ?);
? ? END;??
具體什么樣的表需要定制,這個根據你們的數據庫實際情況,找出具體的表手工收集,下面有個腳本參考一下:
declare
??cursor stale_table is
??select owner, segment_name,
? ?? ?? ?case??when size_gb<0.5 then 30
? ?? ?? ?when size_gb>=0.5 and size_gb<1 then 20
? ?? ?? ?when size_gb >=1 and size_gb<5 then 10
? ?? ?? ?when size_gb>=5 and size_gb<10 then
? ?? ?? ?when size_gb>=10 then 1
? ?? ?? ?end as percent,
? ?? ?? ?8 as degree
? ?? ?? ? from (select owner,segment_name,sum(bytes/1024/1024/1024)size_gb
? ?? ?? ? from dba_segments where owner='' AND SEGMENT_NAME IN
? ?? ?? ? (SELECT /*+ UNNEST */ DISTINCT TABLE_NAME FROM DBA_TAB_STATISTICS WHERE
? ?? ?? ? (LAST_ANALYZED IS NULL OR STALE_STATS='YES') AND OWNER='')
? ?? ?? ? GROUP BY OWNER,SEGMENT_NAME);
? ?? ?? ? BEGIN
FOR STALE IN STALE_TABLE LOOP
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME =>STALE.OWNER,
??TABNAME=>STALE.SEGMENT_NAME,
??ESTIMATE_PERCENT =>STALE.PERCENT,
??METHOD_OPT =>'for all colums size skewonly',---默認oracle 是for all colums size auto
??degree =>8,
??granularity =>'ALL',
??cascade =>true);
??end 1oop;
??end;
(3) 分區表的增量收集:
exec dbms_stats.set_table_prefs('username','TABLENAME','INCREMENTAL','TRUE');
為什么要增量收集,我們這邊有一個log表,記錄用戶下的所有源表的增刪改查,這個表用于用戶程序的增量同步的判斷。
每天的數據量很大,按周的rang分區,查詢的時間都是在最近時間。
----我們暫且不用考慮分區表的設計問題和增量的斷點問題。
3、第三點上面已經解答。
4、
(1)判斷是否過期
(stale_stats='YES' or last_analyzed is??null)可以說明統計信息過期:
??select owner,table_name ,object_type,stale_stats,last_analyzed from dba_tab_statistics where owner ='XX'
and??table_name in('XX')??
(2)oracle默認表的變化量在10%收集統計信息。
有時我們發現有些表數據量變化不大,很久沒有收集統計信息,導致執行計劃問題(oracle 估算基數處在一個臨界點)我們可以根據表的變化率進行微調,從而制定合理的閥值。
查看表的變化率:
select *
??from (select t2.table_name,
? ?? ?? ?? ?? ?t2.partition_name,
? ?? ?? ?? ?? ?t2.subpartition_name,
? ?? ?? ?? ?? ?t2.inserts,
? ?? ?? ?? ?? ?t2.updates,
? ?? ?? ?? ?? ?t2.deletes,
? ?? ?? ?? ?? ?t1.NUM_ROWS,
? ?? ?? ?? ?? ?case
? ?? ?? ?? ?? ???when (t1.NUM_ROWS = 0 or t1.NUM_ROWS is null) then
? ?? ?? ?? ?? ?? ?100
? ?? ?? ?? ?? ???else
? ?? ?? ?? ?? ?? ?trunc((t2.inserts + t2.updates + t2.deletes) / t1.NUM_ROWS * 100,
? ?? ?? ?? ?? ?? ?? ?? ?2)
? ?? ?? ?? ?? ?end "mod_pct(%)",
? ?? ?? ?? ?? ?case
? ?? ?? ?? ?? ???when t1.LAST_ANALYZED is null then
? ?? ?? ?? ?? ?? ?'未分析'
? ?? ?? ?? ?? ???else
? ?? ?? ?? ?? ?? ?to_char(t1.LAST_ANALYZED)
? ?? ?? ?? ?? ?end LAST_ANALYZED,
? ?? ?? ?? ?? ? t2.timestamp,
? ?? ?? ?? ?? ?'begin dbms_stats.gather_table_stats('||'ownname=>'''|| t2.table_owner ||
? ?? ?? ?? ?? ?''','||'tabname=>''' || t2.table_name ||''','||'estimate_percent=>100'||','||'degree=>4'||',cascade => TRUE); end;' EXEC_STATS
? ?? ?? ? from dba_tab_statistics t1, dba_tab_modifications t2
? ?? ?? ?where t1.OWNER = t2.table_owner
? ?? ?? ???and t1.TABLE_NAME = t2.table_name
? ?? ?? ???and DECODE(t1.PARTITION_NAME, t2.partition_name, 0, 1) = 0
? ?? ?? ???and DECODE(t1.SUBPARTITION_NAME, t2.subpartition_name, 0, 1) = 0
? ?? ?? ???and t2.table_owner = '' AND T2.table_name='')
where "mod_pct(%)" >= 0
order by "mod_pct(%)" desc;
調整閥值:
? ?exec dbms_stats.set_table_prefs('用戶名','表名','STALE_PERCENT',1); 這樣表變化率在1%會自動收集
(3) 直方圖什么情況下收集:
oracle默認是for all colums size auto
??oracle文檔中說(文檔 ID 338926.1)中有描述
?? Oracle ?determines the columns to collect histograms based on data distribution and the workload of the columns.
??其實這句話有兩層含義?
??一是必須這個字段是被條件篩選到就是where a=xx
??select object_id from dba_objects where owner='XX' and object_name='XX';
??select name,intcol# from sys.col$ where obj#=XX and name='XX';
??select obj#,intcol#,equality_preds from sys.col_usage$ where obj#=XX;
??這個字段equality_preds要有值
??二是 字段的數據有傾斜
??select count(distinct a) from xx 和select count(*) from xx??數據量不能相等并且數據量大于254,會以HEIGHT BALANCED收集。
??小于254會以FREQUENCY方式收集,當然我們也可以指定桶的大小。
??
5 具體什么情況下用 auto 、repeat??和 skewonly 方式收集統計信息,這個要理解這三個參數的含義。我個人的見解
??auto 使用于系統上線的初期,系統上線穩定了使用repeat方式,如果要自己定制收集使用skewonly方式。
如果發現不足之處,望指出。
總結
以上是生活随笔為你收集整理的数据库优化之统计分析实战篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超级实用的列表提示错误一览显示框
- 下一篇: 七种在BIM实施过程中减少浪费的方法