--問題:關於11g自動收集統計信息
--第一:什么時候收集 ?
--第二:用什么方法去收集?
--第三:收集所有對象 ?還是收集部分對象,怎么判斷 ?
--第四:如果在最新收集統計信息之后出現查詢性能問題 ?怎么恢復舊的統計信息 ?
--自動收集統計信息默認是開啟的
--查看自動收集統計信息是否開啟
SELECT CLIENT_NAME, STATUS FROM DBA_AUTOTASK_CLIENT; SQL> SELECT CLIENT_NAME, STATUS FROM DBA_AUTOTASK_CLIENT; CLIENT_NAME STATUS ------------------------------------------------------------ -------------------- auto optimizer stats collection ENABLED auto space advisor ENABLED sql tuning advisor ENABLED SQL> col client_name for a40 SQL> col task_name for a20 SQL> col operation_name for a40 SQL> SELECT CLIENT_NAME,TASK_NAME,OPERATION_NAME,STATUS FROM dba_autotask_task; CLIENT_NAME TASK_NAME OPERATION_NAME STATUS ---------------------------------------- -------------------- ---------------------------------------- ------------------------ sql tuning advisor AUTO_SQL_TUNING_PROG automatic sql tuning task ENABLED auto optimizer stats collection gather_stats_prog auto optimizer stats job ENABLED
--查看具體操作
SELECT PROGRAM_NAME,PROGRAM_TYPE,PROGRAM_ACTION FROM dba_scheduler_programs WHERE PROGRAM_NAME = 'GATHER_STATS_PROG'; SQL> col program_action for a80 SQL> col program_type for a20 SQL> SELECT PROGRAM_NAME,PROGRAM_TYPE,PROGRAM_ACTION FROM dba_scheduler_programs WHERE PROGRAM_NAME = 'GATHER_STATS_PROG'; PROGRAM_NAME PROGRAM_TYPE PROGRAM_ACTION ------------------------------ -------------------- -------------------------------------------------------------------------------- GATHER_STATS_PROG STORED_PROCEDURE dbms_stats.gather_database_stats_job_proc
--查看具體什么時間做統計信息收集
SQL> SELECT a.WINDOW_NAME,a.REPEAT_INTERVAL,a.duration FROM dba_scheduler_windows a WHERE ENABLED = 'TRUE'; 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 7 rows selected
--可以看到,自動收集統計信息就是通過定時執行dbms_stats.gather_database_stats_job_proc來實現的。
--統計信息收集策略
--在Oracle 11g中,如果參數STATISTICS_LEVEL的值為TYPICAL(默認)或者ALL,
--則DBA_TAB_MODIFICATIONS會
--記錄自上次自動統計信息收集完成之后對表insert、update、delete的操作影響行數以及是否truncate。
--策略:影響行數超過10%或者發生過truncate,那么就會收集該表的統計信息。
--查看歷史執行情況
SELECT * FROM dba_autotask_client_history WHERE client_name LIKE '%stats%';
--禁用以及啟用自動收集統計信息
--啟用 BEGIN DBMS_AUTO_TASK_ADMIN.ENABLE(client_name => 'auto optimizer stats collection', operation => NULL, window_name => NULL); END; --禁用 BEGIN DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'auto optimizer stats collection', operation => NULL, window_name => NULL); END; --關閉單個調度窗口 BEGIN DBMS_AUTO_TASK_ADMIN.disable(client_name => 'auto optimizer stats collection', operation => NULL, window_name => 'MONDAY_WINDOW'); END; / --驗證是否關閉 SELECT window_name, window_next_time, window_active, optimizer_stats FROM dba_autotask_window_clients WHERE window_name = 'MONDAY_WINDOW' ORDER BY window_next_time; SQL> SELECT window_name, window_next_time, window_active, optimizer_stats 2 FROM dba_autotask_window_clients 3 WHERE window_name = 'MONDAY_WINDOW' 4 ORDER BY window_next_time; WINDOW_NAME WINDOW_NEXT_TIME WINDOW_ACTIVE OPTIMIZER_STATS ------------------------------ -------------------------------------------------------------------------------- ------------- --------------- MONDAY_WINDOW 13-DEC-21 10.00.00.000000 PM PRC FALSE DISABLED SQL> --關閉所有調度窗口 BEGIN DBMS_AUTO_TASK_ADMIN.disable ( client_name => 'auto optimizer stats collection', operation => NULL, window_name => NULL); END; / --修改調度窗口的開始時間以及持續時間 --如下示例,將周一時間窗口時間到晚間20點30分 BEGIN DBMS_SCHEDULER.DISABLE(name => '"SYS"."MONDAY_WINDOW"', force => TRUE); END; / BEGIN DBMS_SCHEDULER.SET_ATTRIBUTE(name => '"SYS"."MONDAY_WINDOW"', attribute => 'REPEAT_INTERVAL', VALUE => 'FREQ=WEEKLY;BYDAY=MON;BYHOUR=20;BYMINUTE=30;BYSECOND=0'); END; / BEGIN DBMS_SCHEDULER.ENABLE(name => '"SYS"."MONDAY_WINDOW"'); END; / --驗證修改 SELECT w.window_name, w.repeat_interval, w.duration, w.enabled FROM dba_autotask_window_clients c, dba_scheduler_windows w WHERE c.window_name = w.window_name AND c.optimizer_stats = 'ENABLED' AND c.window_name = 'MONDAY_WINDOW';
--如何恢復統計信息
方法一:
--如何查看統計信息當前保留的天數 select dbms_stats.get_stats_history_retention from dual; SQL> select dbms_stats.get_stats_history_retention from dual; GET_STATS_HISTORY_RETENTION --------------------------- 31 --默認保留31天 --修改保留時間 execute dbms_stats.alter_stats_history_retention (xx); --返回統計信息已經被刪除到的日期(只有在這日期之后的統計信息才能被恢復) select dbms_stats.get_stats_history_availability from dual; GET_STATS_HISTORY_AVAILABILITY --------------------------------------------------------------------------- 05-NOV-21 10.16.00.242000000 PM +08:00 --知道可以恢復的時間之后 --執行恢復 execute dbms_stats.restore_table_stats('owner','table',date); execute dbms_stats.restore_database_stats(date); execute dbms_stats.restore_directory_stats(date); execute dbms_stats.restore_fixed_objects_stats('owner',date); execute dbms_stats.restore_system_stats(date); select stale_stats,last_analyzed from dba_tab_statistics where owner = 'SCOTT' and table_name = 'EMP'; SQL> select stale_stats,last_analyzed 2 from dba_tab_statistics 3 where owner = 'SCOTT' 4 and table_name = 'DEPT'; STALE_STA LAST_ANALYZED --------- ------------------ NO 22-JAN-21 exec DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'DEPT',ESTIMATE_PERCENT=>10,method_opt=>'for all columns size 1',cascade=>true,force=>true,degree=>8); SQL> exec DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'DEPT',ESTIMATE_PERCENT=>10,method_opt=>'for all columns size 1',cascade=>true,force=>true,degree=>8); PL/SQL procedure successfully completed. SQL> select stale_stats,last_analyzed 2 from dba_tab_statistics 3 where owner = 'SCOTT' 4 and table_name = 'DEPT'; STA LAST_ANALYZE --- ------------ NO 08-DEC-21 execute dbms_stats.restore_table_stats('SCOTT','DEPT','05-NOV-21 10.16.00.242000000 PM +08:00'); ERROR at line 1: ORA-20006: Unable to restore statistics , statistics history not available ORA-06512: at "SYS.DBMS_STATS", line 28286 ORA-06512: at "SYS.DBMS_STATS", line 28305 ORA-06512: at line 1 execute dbms_stats.restore_table_stats('SCOTT','DEPT','07-DEC-21 10.16.00.242000000 PM +09:00'); SQL> execute dbms_stats.restore_table_stats('SCOTT','DEPT','07-DEC-21 10.16.00.242000000 PM +09:00'); PL/SQL procedure successfully completed. SQL> select stale_stats,last_analyzed 2 from dba_tab_statistics 3 where owner = 'SCOTT' 4 and table_name = 'DEPT'; STALE_STA LAST_ANALYZED --------- ------------------ NO 22-JAN-21 --可以看到,表的統計信息又回到上次收集的時間點。
方法二:
--在收集某個表的統計信息,或者某個用戶的統計信息或全庫的統計信息之前,可以用下面的方法來導出和導入統計信息。 --創建統計信息歷史保留表 exec dbms_stats.create_stat_table(ownname=> 'SCOTT' ,stattab=> 'stat_table' ); --導出整個scheme的統計信息 exec dbms_stats.export_schema_stats(ownname=>'SCOTT' ,stattab => 'stat_table' ); --導入表的歷史統計信息 exec dbms_stats.import_table_stats(ownname=>'SCOTT',tabname=>'TEST',stattab=>'stat_table'); --如果進行分析后,大部分表的執行計划都走錯,需要導回整個scheme的統計信息 exec dbms_stats.import_schema_stats(ownname=>'SCOTT' ,stattab=>'stat_table' ); 示例: SQL> select stale_stats,last_analyzed 2 from dba_tab_statistics 3 where owner = 'SCOTT' 4 and table_name = 'EMP'; STALE_STA LAST_ANALYZED --------- ------------------ NO 22-JAN-21 SQL> exec dbms_stats.create_stat_table(ownname=> 'SCOTT' ,stattab=> 'stat_table' ); PL/SQL procedure successfully completed. SQL> exec dbms_stats.export_schema_stats(ownname=>'SCOTT' ,stattab => 'stat_table' ); PL/SQL procedure successfully completed. SQL> exec DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'EMP',ESTIMATE_PERCENT=>10,method_opt=>'for all columns size 1',cascade=>true,force=>true,degree=>8); PL/SQL procedure successfully completed. SQL> select stale_stats,last_analyzed 2 from dba_tab_statistics 3 where owner = 'SCOTT' 4 and table_name = 'EMP'; STALE_STA LAST_ANALYZED --------- ------------------ NO 08-DEC-21 SQL> exec dbms_stats.import_table_stats(ownname=>'SCOTT',tabname=>'EMP',stattab=>'stat_table'); PL/SQL procedure successfully completed. SQL> select stale_stats,last_analyzed 2 from dba_tab_statistics 3 where owner = 'SCOTT' 4 and table_name = 'EMP'; STALE_STA LAST_ANALYZED --------- ------------------ NO 22-JAN-21