--问题:关于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