在某些情况下,可能需要确保数据库的部分对象统计信息不可用或者不允许修改,这是因为需要使用动态采样,或者必须使用非最新的对象统计信息(例如,因为某些表的内容变化非常频繁,你希望只有在这些表包含了一组有代表性的数据时才小心地收集其状态),也可能因为收集统计信息不可行(例如,出现了bug)。
可以通过执行下面的dbms_stats包中的存储过程来显式锁定对象统计信息。注意这些锁和通常所说的数据库锁没有任何关系。实际上,它们是在数据字典的表级别设置的简单标记。
Ø lock_schema_stats 锁定属于某个模式下的所有表的对象统计信息:
dbms_stats.lock_schema_stats(ownname =>
user);
Ø lock_table_stats 锁定单张表的对象统计信息:
dbms_stats.lock_table_stats(ownname =>
user, tabname =>'T');
当然,也可以移除这些锁,你可以通过以下存储过程中的一个来完成。
Ø unlock_schema_stats 解除某个模式下所有表的对象统计信息上的锁定:
dbms_stats,unlock_schema_stats(ownname
=> user);
Ø unlock_table_stats 解除单张表的对象统计信息上的锁定:
dbms_stats.unlock_table_stats(ownname =>
user, tabname =>'T');
要执行这四个存储过程,需要以所有者身份登录或者拥有analyze any系统权限。
锁定了某张表的对象统计信息时,会将与该表相关的所有对象统计信息(包括表统计信息、列统计信息、直方图以及所有依赖索引的索引统计信息)都视为锁定的。
锁定了某张表的对象统计信息的情况下,dbms_stats包中修改单张表的对象统计信息的过程(例如gather_table_stats)会引发一个错误(ORA-20005)。与此相反,操作多张表的过程(例如gather_schema_stats)会跳过锁定的表。大多数修改对象统计信息的过程能够通过将force参数设置为TRUE来覆盖锁定。下面的例子演示了这种行为(完整示例参见lock_statistics.sql脚本):
BEGIN
dbms_stats.lock_schema_stats(ownname => user);
END;
/
BEGIN
dbms_stats.gather_schema_stats(ownname => user);
END;
/
BEGIN
dbms_stats.gather_table_stats(ownname => user,
tabname =>
'T');
END;
/
ERROR at line 1:
ORA-20005: object statistics are locked
(stattype = ALL)
ORA-06512: at
"SYS.DBMS_STATS",line 33859
ORA-06512: at line 2
BEGIN
dbms_stats.gather_table_stats(ownname => user,
tabname =>
'T',
force => TRUE);
END;
/
要想知道哪些表的对象统计信息被锁定了,可以使用类似下面这样的查询:
select table_name from user_tab_statistics
where stattype_locked is not null;
要知道并非只有dbms_stats包会收集对象统计信息,因此,也不是只有它才会受对象统计信息上的锁影响。实际上, ANALYZE、CREATE INDEX和ALTER INDEX语句,以及12.1及之后版本的CTAS 语句和向空表执行直接路径插入,也都会收集对象统计信息。
ANALYZE语句会在被明确告知时收集对象统计信息。但是,如本章开头所述,你不应该再使用这个语句收集统计信息。其余的语句会在执行它们分配的任务时自动收集对象统计信息。这样做很有意义,因为执行这些SQL语句时收集统计信息的开销可以忽略不计。所以,锁定了表的对象统计信息时,以上这些SQL语句的行为可能会有所不同或者甚至会失败。下面的例子作为上一个例子的延续,展示了这种行为:
SQL> ANALYZE TABLE t COMPUTE STATISTICS;
ANALYZE TABLE t COMPUTE STATISTICS
*
ERROR at line 1:
ORA-38029:object statistics are locked
SQL> ANALYZE TABLE t VALIDATE STRUCTURE;
SQL> ALTER INDEX t_pk REBUILD COMPUTE
STATISTICS;
ALTER INDEX t_pk REBUILD COMPUTE STATISTICS
*
ERROR at line 1:
ORA-38029: object statistics are locked
SQL> ALTER INDEX t_pk REBUILD;
SQL> CREATE INDEX t_i ON t(pad) COMPUTE
STATISTICS;
CREATE INDEX t_i ON t(pad) COMPUTE
STATISTICS
*
ERROR at line 1:
ORA-38029: object statistics are locked
SQL> CREATE INDEX t_i ON t(pad);
注意, SQL语句CREATE INDEX和ALTER INDEX只有在指定了不推荐使用的COMPUTE STATISTICS子句时才会失败。因为这些SQL语句都会默认收集对象统计信息,使用COMPUTE STATISTICS子句完全没有意义。