ORA-04030报错后应先定位高内存SQL、检查workarea执行模式(optimal/one-pass/multipass)及自动管理是否生效,再验证pga_aggregate_target与pga_aggregate_limit配置是否合理,而非直接调大参数。

ORA-04030报错后,先别调pga_aggregate_target
ORA-04030 出现时,直接增大 pga_aggregate_target 往往治标不治本。真正要做的,是确认是不是 PGA 真的“不够”,还是某几条 SQL 在疯狂吃内存、或 workarea 预估严重失准。
典型干扰信号包括:sorts (disk)、hash joins (disk) 统计值飙升,但 PGA memory used 总量没爆——说明不是总量缺,而是单次操作分配失败或预估过小。
- 查
v$pgastat看total PGA allocated是否接近pga_aggregate_target,但更关键的是看over allocation count(非零就说明已触发强制扩堆) - 运行
SELECT * FROM v$sysmetric WHERE metric_name = 'PGA Memory MBytes',观察 1 分钟内是否剧烈抖动(>20% 波动),抖动大基本可锁定为 SQL 级别异常 - 注意:如果
pga_aggregate_limit被设得太紧(比如仅 3MB × processes),哪怕pga_aggregate_target没满,也会因硬限触发acknowledge over PGA limit等待事件
从AWR报告里定位“吃内存”的SQL
AWR 的「SQL Statistics → Memory Statistics」页是核心入口,重点盯三列:
-
Workarea executions – optimal:越高越好,理想应 >95% -
Workarea executions – one-pass:>5% 就要警惕,说明部分排序/哈希开始落盘 -
Workarea executions – multipass:只要非零,必须立即干预——这不是配置问题,是 SQL 或数据倾斜导致 Oracle 低估了所需内存
再往下翻到「SQL ordered by PGA Memory」,直接看到消耗 Top N 的 sql_id。注意这个列表只统计执行时间 ≥1 秒的 SQL,短而猛的内存操作(如单次大排序)可能漏掉,需结合 ASH 补充:
SELECT sql_id, ROUND(SUM(pga_memory_used)/1024/1024, 1) AS pga_mb FROM dba_hist_active_sess_history a JOIN dba_hist_sqlstat s USING (sql_id) WHERE sample_time > SYSDATE - 1 AND session_state = 'ON CPU' GROUP BY sql_id ORDER BY pga_mb DESC FETCH FIRST 5 ROWS ONLY;
如果结果为空,检查 DBA_HIST_ACTIVE_SESS_HISTORY 保留策略是否太短(默认 8 天),或 ASH 采样是否被禁用。
确认workarea自动管理是否真在生效
很多 PGA 问题其实源于手动参数残留,让 pga_aggregate_target 形同虚设。
- 运行
SHOW PARAMETER workarea_size_policy,确保返回AUTO;若为MANUAL,立刻改回来:ALTER SYSTEM SET workarea_size_policy=AUTO; - 查
SHOW PARAMETER sort_area_size和SHOW PARAMETER hash_area_size,二者必须为0或NULL;非零值会强制绕过自动管理 - 检查是否有 SQL 带
+ OPT_PARAM('_smm_max_size' ...)这类 hint,它会覆盖全局设置,且不会出现在 AWR 的 SQL 文本里,只能靠 SQL Monitor 或 10046 trace 抓
调参前必须验证的两个底线指标
PGA Memory Advisory 页里的建议值不能照单全收,只认两个硬条件:
-
Estd PGA Overalloc Count = 0:这是底线,不满足就一定不够 -
Estd Extra W/A MB Read/Written to Disk不再随目标增大而下降:比如从 2.5GB → 3GB,该值从 12.1MB → 12.09MB,基本持平,再加无意义
特别注意:如果 AWR 快照期间跑过一次大报表,W/A MB Processed 会被拉高,导致建议值虚高。应人工剔除非典型负载周期(比如凌晨批量报表时段)再重跑 AWR。
真正难的不是算出那个数字,而是判断当前业务负载是否稳定、SQL 是否已优化到位——没压测过、没重写过可疑 SQL,光调内存只是把问题往后拖。


















