问题现象
客户oracle19c单机环境时常出现pga不足告警
根据AWR分析,该环境业务负载较低,PGA消耗长期维持在10%左右
PGA_AGGREGATE_LIMIT介绍
通常情况下,我们是通过设置参数 PGA_AGGREGATE_TARGET 来确定一个 PGA 的使用量。但是,在Oracle 12C 之前版本,PGA_AGGREGATE_TARGET 不会硬限制 PGA 内存使用量,,有时候会超出上限,导致 PGA 内存使用无法准确掌控。
从 Oracle 12C 开始,允许数据库管理员设置 PGA(Program Global Area)内存的使用上限,可以对 PGA 的使用量进行硬性限制。如果 PGA 使用超出设置的值,Oracle 数据库会中止或终止占用最多、不可调整 PGA 内存的会话或进程。当实例中的私有内存超出 PGA_AGGREGATE_LIMIT 初始化参数中指定的限制时,会发生 ORA-04036 错误。使用Program Global Area (PGA) 内存的最大会话被中断以低于限制。
此错误通常是由于使用、应用程序或配置问题引起的,但在某些情况下,它们可能是由 bug 问题引起的。
分析
检查日志发现,pga不足发生的时间段比较固定,都维持在凌晨4、5点之间,结合监控的PGA使用情况可以发现,该时间段的PGA会出现异常升高,在达到PGA_AGGREGATE_TARGET限制后,断崖式回落。
问题事件段与统计信息的自动收集任务高度重合,通常在启动统计信息任务后20-50分钟会形成PGA异常增长,怀疑是BUG造成。
查询官网,发现类似BUG,官方文档(ID 2856094.1)
BUG原因:当数据库在执行DBMS_STATS.GATHER_FIXED_OBJECTS_STATS而产生的大量子游标存在表X$KQLFSQCE中,导致表的大小非常大,并且需要使用大量的私有内存来查询表。
DBMS_STATS.GATHER_FIXED_OBJECTS_STATS用于收集固定对象(fixed objects)的统计信息,这些固定对象包括数据字典基表和其他内部表,它们的统计信息对于优化器生成高效的SQL执行计划至关重要。
根据文档提供的语句,对比问题数据库和正常数据库,能看到明显不同
正常数据库
问题数据库
处理方法
a) 更新补丁Patch 33163187
b) 修改参数
1) alter system set "_fix_control"='17443547:0'
2) 或者
alter system set "_optimizer_extended_cursor_sharing"='none'
alter system set "_optimizer_extended_cursor_sharing_rel"='none'
建议
同时发现Optimizer Statistics Advisor 功能 也会异常消耗PGA,建议关闭。Optimizer Statistics Advisor 不是自动统计信息收集的 JOB,是Oracle数据库中的一种内置诊断工具,从12.2版本开始提供,用于分析优化器统计信息的收集方式并提出建议。关闭这个功能完全不影响自动统计信息收集,不会对数据库造成任何影响。
关闭 Optimizer Statistics Advisor 功能,官方文档 (Doc ID 2728765.1)
在 Oracle 12CR2 ~ 19C 版本中想要关闭这个功能,需要打一个补丁 Bug 26749785 : PERF_DIAG: NEED TO HAVE MORE CONTROL IN DICTIONARY FOR AUTO_STATS_ADVISOR_TASK 后才能实现,21C 开始默认支持。
打补丁之后新增了 “AUTO_STATS_ADVISOR_TASK” 的属性设置,可以手动启用/禁用 AUTO_STATS_ADVISOR_TASK。
检查当前属性:
SQL> select dbms_stats.get_prefs('AUTO_STATS_ADVISOR_TASK') from dual;
DBMS_STATS.GET_PREFS('AUTO_STATS_ADVISOR_TASK')
--------------------------------------------------------------------------------
TRUE
禁用统计顾问:
SQL> exec dbms_stats.set_global_prefs('AUTO_STATS_ADVISOR_TASK','FALSE');
PL/SQL procedure successfully completed.
SQL> select dbms_stats.get_prefs('AUTO_STATS_ADVISOR_TASK') from dual;
DBMS_STATS.GET_PREFS('AUTO_STATS_ADVISOR_TASK')
--------------------------------------------------------------------------------
FALSE