How restore CBO statistics

从Oracle10g开始,当对一个表收集统计信息时,旧的统计信息会被保留了,因此当出现新收集的统计信息引起性能问题时,可以还原旧统计信息。缺省情况下统计信息会被保留31天,但可以执行execute DBMS_STATS.ALTER_STATS_HISTORY_RETENTION (days)来进行修改,days为你所指定的天数。

SQL> select DBMS_STATS.GET_STATS_HISTORY_RETENTION from dual;

GET_STATS_HISTORY_RETENTION
---------------------------
                         31
SQL> execute DBMS_STATS.ALTER_STATS_HISTORY_RETENTION(60);
 
PL/SQL procedure successfully completed
 
SQL> select DBMS_STATS.GET_STATS_HISTORY_RETENTION from dual;
 
GET_STATS_HISTORY_RETENTION
---------------------------
                         60

在修改统计信息保留天数时要确保sysaux表空间有足够的表空间大小来存储统计信息,防止统计信息写满sysaux表空间。

可以执行以下语句来查询统计信息的保留天数:

SQL> select DBMS_STATS.GET_STATS_HISTORY_RETENTION from dual;

GET_STATS_HISTORY_RETENTION
---------------------------
                         31

执行以下语句可以查询被保留时间最久的统计信息,早于这个时间点的统计信息已经被删除。任何要求还原这个时间点及之前的统计信息都会报错”ORA-20006: Unable to restore statistics , statistics history not available”

SQL> select DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY from dual;

GET_STATS_HISTORY_AVAILABILITY
--------------------------------------------------------------------------------
10-APR-16 10.50.36.929152000 PM +08:00

SQL> execute dbms_stats.restore_table_stats ('SCOTT','EMP','10-APR-16 10.50.36.929152000 PM +08:00');

begin dbms_stats.restore_table_stats ('SCOTT','EMP','10-APR-16 10.50.36.929152000 PM +08:00'); end;

ORA-20006: Unable to restore statistics , statistics history not available
ORA-06512: at "SYS.DBMS_STATS", line 17063
ORA-06512: at "SYS.DBMS_STATS", line 17080
ORA-06512: at line 2

要想找到表的统计信息收集历史信息可以执行以下查询

SQL> select TABLE_NAME, STATS_UPDATE_TIME from dba_tab_stats_history where table_name='PM_BILL';

TABLE_NAME                     STATS_UPDATE_TIME
------------------------------ --------------------------------------------------------------------------------
PM_BILL                        12-APR-16 10.06.00.454894 PM +08:00
PM_BILL                        29-APR-16 10.11.24.030930 PM +08:00
PM_BILL                        01-MAY-16 04.44.42.324357 AM +08:00
PM_BILL                        02-MAY-16 07.03.38.762862 AM +08:00
PM_BILL                        03-MAY-16 09.33.53.942353 AM +08:00

还原统计信息可以根据需要选择以下几种方式:
execute DBMS_STATS.RESTORE_TABLE_STATS (‘owner’,’table’,date)
execute DBMS_STATS.RESTORE_DATABASE_STATS(date)
execute DBMS_STATS.RESTORE_DICTIONARY_STATS(date)
execute DBMS_STATS.RESTORE_FIXED_OBJECTS_STATS(date)
execute DBMS_STATS.RESTORE_SCHEMA_STATS(‘owner’,date)
execute DBMS_STATS.RESTORE_SYSTEM_STATS(date)

下面介绍一个还原指定表统计信息的操作:
1.查询表pm_bill的统计信息,显示有232277行记录。

SQL> select table_name,num_rows,blocks,empty_blocks,sample_size from user_tables where table_name='PM_BILL';

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS SAMPLE_SIZE
------------------------------ ---------- ---------- ------------ -----------
PM_BILL                            232277       5164            0       69683

2.查询表pm_bill收集的统计信息的次数

SQL> select TABLE_NAME, STATS_UPDATE_TIME from dba_tab_stats_history where table_name='PM_BILL';

TABLE_NAME                     STATS_UPDATE_TIME
------------------------------ --------------------------------------------------------------------------------
PM_BILL                        12-APR-16 10.06.00.454894 PM +08:00
PM_BILL                        29-APR-16 10.11.24.030930 PM +08:00
PM_BILL                        01-MAY-16 04.44.42.324357 AM +08:00
PM_BILL                        02-MAY-16 07.03.38.762862 AM +08:00
PM_BILL                        03-MAY-16 09.33.53.942353 AM +08:00

3.查询表pm_bill中真实的记录数为235032与统计信息中记录的232277有差异

SQL> select count(*) from pm_bill;

  COUNT(*)
----------
    235032

4.查询统计信息保留的最早时间

SQL> select DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY from dual;

GET_STATS_HISTORY_AVAILABILITY
--------------------------------------------------------------------------------
10-APR-16 10.50.36.929152000 PM +08:00

5.对表pm_bill收集统计信息,采样比例使用100%

SQL> exec dbms_stats.gather_table_stats(ownname => 'insur_changde',tabname => 'pm_bill',estimate_percent => 100,method_opt => 'for all columns size repeat');

PL/SQL procedure successfully completed

6.查询表pm_bill的统计信息,可以看到重新收集统计信息后表的记录数与真实记数一样为235032

SQL> select table_name,num_rows,blocks,empty_blocks,sample_size from user_tables where table_name='PM_BILL';

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS SAMPLE_SIZE
------------------------------ ---------- ---------- ------------ -----------
PM_BILL                            235032       5290            0      235032

SQL> select TABLE_NAME, STATS_UPDATE_TIME from dba_tab_stats_history where table_name='PM_BILL';

TABLE_NAME                     STATS_UPDATE_TIME
------------------------------ --------------------------------------------------------------------------------
PM_BILL                        12-APR-16 10.06.00.454894 PM +08:00
PM_BILL                        29-APR-16 10.11.24.030930 PM +08:00
PM_BILL                        01-MAY-16 04.44.42.324357 AM +08:00
PM_BILL                        02-MAY-16 07.03.38.762862 AM +08:00
PM_BILL                        03-MAY-16 09.33.53.942353 AM +08:00
PM_BILL                        12-MAY-16 03.06.43.688976 PM +08:00

7.将表pm_bill的统计信息还原到03-MAY-16 09.33.53.942353 AM +08:00这个时间点

SQL> exec dbms_stats.restore_table_stats ('insur_changde','pm_bill','03-MAY-16 09.33.53.942353 AM +08:00');

PL/SQL procedure successfully completed

SQL> select TABLE_NAME, STATS_UPDATE_TIME from dba_tab_stats_history where table_name='PM_BILL';

TABLE_NAME                     STATS_UPDATE_TIME
------------------------------ --------------------------------------------------------------------------------
PM_BILL                        12-APR-16 10.06.00.454894 PM +08:00
PM_BILL                        29-APR-16 10.11.24.030930 PM +08:00
PM_BILL                        01-MAY-16 04.44.42.324357 AM +08:00
PM_BILL                        02-MAY-16 07.03.38.762862 AM +08:00
PM_BILL                        03-MAY-16 09.33.53.942353 AM +08:00
PM_BILL                        12-MAY-16 03.06.43.688976 PM +08:00
PM_BILL                        12-MAY-16 03.12.55.388126 PM +08:00

7 rows selected

从上面的查询结果可以看到,表pm_bill的统计信息收集的历史信息多了一条时间为12-MAY-16 03.12.55.388126 PM +08:00
的记录,这是我们还原统计信息所产生的。

查询表pm_bill的统计信息,可以看到统计信息中记录的表的记录数恢复成了232277行

SQL> select table_name,num_rows,blocks,empty_blocks,sample_size from user_tables where table_name='PM_BILL';

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS SAMPLE_SIZE
------------------------------ ---------- ---------- ------------ -----------
PM_BILL                            232277       5164            0       69683

这个功能当新收集统计信息后,如果引起了性能问题可以做为一个临时手段还解决性能问题。

发表评论

电子邮件地址不会被公开。