- 问题版本:oracle 12.2.0.1及更高版本
最近给客户检查时发现客户的SYSAUX表空间随着业务量越增越多,排查确认是AUTO_STATS_ADVISOR_TASK客户环境中出现两种情况:一是手工执行
exec prvt_advisor.delete_expired_tasks后,过期的统计信息顾问记录仍未被清除;二是本应自动清理的过期统计信息顾问记录未按时清除。经测试确认,该问题为 BUG 38326922(涉及版本≥19.27 且 < 25.1),需通过打补丁(Patch 38326922)或升级至 19.29 及以上版本修复。若自查发现最旧的统计信息时间早于保留天数,且数据库版本在 19.26-19.28 左右,大概率是该 BUG 导致,建议尽早处理。
确认V$SYSAUX_OCCUPANTS中空间使用率占用最高的一项:
sql
SET LINES 120
COL OCCUPANT_NAME FORMAT A30
SELECT OCCUPANT_NAME,SPACE_USAGE_KBYTES/1024/1024 AS SPACE_USAGE_GB FROM V$SYSAUX_OCCUPANTS ORDER BY SPACE_USAGE_KBYTES DESC;

查询DBA_SEGMENTS中SUSAUX表空间空间使用率最高的SEGMENT:
SELECT * FROM (SELECT SEGMENT_NAME,OWNER,TABLESPACE_NAME,BYTES/1024/1024 "SIZE(MB)",SEGMENT_TYPE FROM DBA_SEGMENTS WHERE TABLESPACE_NAME='SYSAUX' ORDER BY BYTES DESC) WHERE ROWNUM<=10;

确认使用率最大的为SM/ADVISOR与WRI$_ADV_OBJECTS时,可参考下方方法进行清理旧的Statistics Advisor
删除统计信息顾问任务(STATS_ADVISOR_ASK)
方法一:清空大量统计信息(AUTO_STATS_ADVISOR_TASK的数据全部清空,即使是bug版本也可以直接清理)
以sysdba身份执行以下命令:
DECLARE
v_tname VARCHAR2(32767);
BEGIN
v_tname := 'AUTO_STATS_ADVISOR_TASK';
DBMS_STATS.DROP_ADVISOR_TASK(v_tname);
END;
/
注:情况后重新初始化才会有AUTO_STATS_ADVISOR_TASK的任务
EXEC DBMS_STATS.INIT_PACKAGE();

方法二:手动清除过期的统计信息顾问记录
清除EXECUTION_DAYS_TO_EXPIRE的日期之前的AUTO_STATS_ADVISOR_TASK
sql
exec prvt_advisor.delete_expired_tasks;
保留天数参考:
sql
SELECT NAME,VALUE FROM wri$_adv_parameters WHERE task_id in (
SELECT ID FROM SYS.WRI$_ADV_TASKS WHERE NAME = 'AUTO_STATS_ADVISOR_TASK' and owner_name = 'SYS'
) AND NAME IN ('DAYS_TO_EXPIRE','EXECUTION_DAYS_TO_EXPIRE');
为避免delete数据量过大导致undo爆掉,可考虑下方的循环删除的方式:
清除30天前的统计信息,每次删除过期20天的任务
set serveroutput on
DECLARE
v_oldest INTEGER := 730; -- 最老的数据为2年
v_increment INTEGER := 30; -- 删除循环步长30天
v_cur_age INTEGER;
v_min_age INTEGER := 30; -- 保留一个月 ,该参数会影响EXECUTION_DAYS_TO_EXPIRE的结果
BEGIN
v_cur_age := v_oldest;
WHILE v_cur_age >= v_min_age LOOP
dbms_sqltune.set_tuning_task_parameter(task_name => 'AUTO_STATS_ADVISOR_TASK', parameter => 'EXECUTION_DAYS_TO_EXPIRE', value => v_cur_age);
prvt_advisor.delete_expired_tasks;
v_cur_age := v_cur_age - v_increment;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Execution halted with error number ' || sqlerrm);
END;
/
已执行的的统计信息时间参考SQL
sql
select task_id, execution_name, execution_start, status
from dba_advisor_executions
where TASK_NAME='AUTO_STATS_ADVISOR_TASK'
order by execution_start desc;
删除该任务后,重新组织表WRI$_ADV_ADTS及其索引
SQL> ALTER TABLE WRI$_ADV_OBJECTS MOVE;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_IDX_01 REBUILD;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_PK REBUILD;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_IDX_02 REBUILD;
-
重建后确认索引是可用的
column index_name format a30
select index_name,status from dba_indexes where table_name='WRI$_ADV_OBJECTS' and index_type like '%NORMAL'; -
多租户环境,需按照以下方式进行重建:
SQL> alter session set container=emrepdb;
SQL> exec dbms_pdb.exec_as_oracle_script('ALTER TABLE WRI_ADV_OBJECTS MOVE'); SQL> exec dbms_pdb.exec_as_oracle_script('ALTER INDEX WRI_ADV_OBJECTS_PK REBUILD');
SQL> exec dbms_pdb.exec_as_oracle_script('ALTER INDEX WRI_ADV_OBJECTS_IDX_01 REBUILD'); SQL> exec dbms_pdb.exec_as_oracle_script('ALTER INDEX WRI_ADV_OBJECTS_IDX_02 REBUILD');
测试执行参考命令
- 手工执行AUTO_STATS_ADVISOR_TASK
sql
DECLARE
v_tname VARCHAR2(128) := 'AUTO_STATS_ADVISOR_TASK';
BEGIN
-- execute the task
v_tname := DBMS_STATS.EXECUTE_ADVISOR_TASK(v_tname);
END;
/
- 修改AUTO_STATS_ADVISOR_TASK的过期日期
sql
EXEC DBMS_ADVISOR.SET_TASK_PARAMETER(task_name=> 'AUTO_STATS_ADVISOR_TASK', parameter=> 'EXECUTION_DAYS_TO_EXPIRE', value => 10);
- 确认保留日期
sql
select TASK_NAME,parameter_name, parameter_value FROM DBA_ADVISOR_PARAMETERS WHERE task_name='AUTO_STATS_ADVISOR_TASK' and PARAMETER_NAME='EXECUTION_DAYS_TO_EXPIRE';
- 确认执行情况
sql
select task_id, execution_name, execution_start, status
from dba_advisor_executions
where TASK_NAME='AUTO_STATS_ADVISOR_TASK'
order by execution_start desc;