无论何时通过dbms_stats包收集了对象统计信息,或者从11.2版本开始,用ALTER INDEX语句取代简单地使用新的统计信息覆盖当前统计信息,当前统计信息都会被存储到其他数据字典表中,并保存一份在保留期内出现变化的所有历史记录。其用途是,万一新的统计信息导致了效率低下的执行计划,可以还原旧的统计信息。
对象统计信息在历史中保存一段由保留期指定的时间间隔(系统统计信息也是这样,因为它们是由相同的基础功能维护的)。默认值是31天。可以通过调用dbms_stats包 的get_stats_history_retention函数来显示当前值,如下所示:
select
dbms_stats.get_stats_history_retention()AS retention FROM dual;
要修改保留期,可以使用dbms_stats包提供的alter_stats_history_retention存储过程。下面是一个将保留期设置为14天的调用例子:
dbms_stats.alter_stats_history_retention(retention
=>14);
注意,使用alter_stats_history_retention存储过程时,下面的值有特殊意义。
Ø NULL会将保留期设置为默认值。
Ø 0会禁用历史记录。
Ø -1会禁用历史记录的清除。
将statistics_level初始化参数设置为typical(默认值)或者all时,时间超出保留期的统计信息会被自动清除掉。一旦有必要进行手工清除时,可以使用dbms_stats包提供的purge_stats存储过程。下面的调用清除历史记录中所有超过14天的统计信息:
dbms_stats.purge_stats(before_timestamp
=> systimestamp - INTERVAL '14' DAY);
要执行alter_stats_history_retention和purge_stats存储过程,需要有analyze any和analyze any dictionary系统权限。
如果想知道对于一张给定的表它的对象统计信息何时被修改过, user_tab_stats_history数据字典视图可以提供所有必要的信息。当然了,还有dba、all以及12.1版本中多租户环境下的cdb版本可用。下面是一个例子。通过下面的查询,可以显示sys模式下的tab$表的对象统计信息的修改时间:
select stats_update_time
FROM dba_tab_stats_history
WHERE owner='SYS' and table_name='TAB$';
无论什么时候,如果有必要,都可以从历史记录中还原统计信息。出于这个目的,dbms_stats提供以下存储过程。
Ø restore_database_stats 为整个数据库还原对象统计信息。
Ø restore_dictionary_stats 为数据字典还原对象统计信息。
Ø restore_fixed_objects_stats 为固定表及其索引还原对象统计信息。
Ø restore_schema_stats 为单个模式还原对象统计信息。
Ø restore_table_stats 为单张表还原对象统计信息。
除了指定目标的参数之外(例如,restore_table_stats过程的模式和表名),所有这些存储过程都提供以下参数。
Ø as_of_timestamp 指定将统计信息还原至某一特定的时间点。
Ø force 指定是否可以覆盖锁定的统计信息。注意统计信息上的锁也是历史记录的一部分。这就意味着关于统计信息的状态信息(锁定与否)也可以被还原。默认值为FALSE。
Ø no_invalidate 指定依赖于被覆盖的统计信息的游标是否失效。这个参数接受的值为TRUE、FALSE,还有dbms_stats.auto_invalidate。默认值是dbms_stats.auto_invalidate。
下面的调用将SH模式下的对象统计信息还原为一天以前使用的值。因此,force参数被设置为TRUE时,即使当前统计信息是锁定状态也会被还原:
dbms_stats.restore_schma_stats(
ownname =>'SH',
as_of_timestamp => systemstamp -
interval '1' day,
force => true
);