内存抖动本质是PGA分配失败或workarea预估失准导致频繁落盘、重试甚至会话卡死,ASH是唯一可定位秒级抖动的证据源,须查gv$而非v$,重点关注session_state='ON CPU'且event含'PGA'或'memory'的连续采样。

内存抖动引发的性能骤降,本质是 PGA 分配失败或 workarea 预估严重失准导致的频繁落盘、重试甚至会话卡死,ASH 是唯一能抓到“哪一秒开始抖、哪条 SQL 在抖、抖成什么样子”的证据源——AWR 报告里看不到抖动,只看到平均值掩盖后的“一切正常”。
查 gv$active_session_history 而非 v$,尤其在 RAC 环境
RAC 下单节点查 v$active_session_history 会漏掉其他实例上的抖动会话,必须用 gv$active_session_history。常见错误是脚本里写死了 v$ 视图,结果只看到本节点 2 条等待,实际另外两个节点各有 17 条 PGA memory allocation 或 acknowledge over PGA limit 采样,根本对不上故障强度。
- 确认是否 RAC:
SELECT * FROM v$option WHERE parameter = 'Real Application Clusters';返回 TRUE 就必须用gv$ - 别依赖 DBA_HIST_ACTIVE_SESS_HISTORY:它默认每 10 秒抽一条样本,秒级抖动直接被跳过
- 时间过滤要带时区精度:
SAMPLE_TIME > SYSTIMESTAMP - INTERVAL '3' MINUTE,避免因 NLS 设置导致隐式转换丢数据
重点盯 session_state = 'ON CPU' + event 包含 'PGA' 或 'memory'
内存抖动不是“等”,而是“执行中突然卡住分配内存”,所以不能只筛 event LIKE '%wait%'。真正线索藏在 session_state = 'ON CPU' 且 event 字段出现异常值的组合里:
-
event = 'PGA memory allocation':进程正在尝试向 OS 申请新内存页,若连续多秒出现,说明pga_aggregate_limit已触顶或 OS 内存不足 -
event = 'acknowledge over PGA limit':Oracle 主动拒绝分配,强制让会话等待,这是硬限生效的铁证 -
event = 'latch: shared pool'配合高session_state = 'ON CPU':共享池碎片化严重,解析/分配内存时自旋加剧,CPU 白忙 - 注意
sql_id为空的样本:很可能是 PL/SQL 匿名块反复调用DBMS_LOB.CREATETEMPORARY或递归硬解析,这类不走 SQL 缓存,ASH 里只有program和module
聚合连续秒级采样,识别“抖动证据链”
单条 ASH 记录没意义,内存抖动一定表现为“同一 sql_id + 同一 event + 连续 3 秒以上密集采样”。用以下逻辑过滤比看 Top Event 更准:
SELECT sql_id, event, COUNT(*) cnt,
TO_CHAR(MIN(sample_time), 'HH24:MI:SS') min_sec,
TO_CHAR(MAX(sample_time), 'HH24:MI:SS') max_sec
FROM gv$active_session_history
WHERE sample_time >= SYSTIMESTAMP - INTERVAL '5' MINUTE
AND (event LIKE '%PGA%' OR event LIKE '%memory%' OR event = 'latch: shared pool')
AND session_state = 'ON CPU'
GROUP BY sql_id, event
HAVING COUNT(*) >= 3
ORDER BY cnt DESC;- 用
HAVING COUNT(*) >= 3强制要求连续性,避免把偶发噪声当根因 - 别加
DISTINCT sql_id:同一sql_id可能对应多个sql_plan_hash_value,抖动往往只发生在某个子游标上 - 如果结果为空,立刻检查:
SELECT pga_aggregate_limit/1024/1024 FROM v$pgastat;是否被设得过小(比如仅 512MB),或者 OS 层vm.overcommit_memory设为 2 导致 malloc 失败
关联 PGA 使用趋势与 OS 内存状态
ASH 告诉你“谁在抖”,但不告诉你“为什么抖”。必须立刻补一手验证:
- 查当前 PGA 实时压力:
SELECT metric_name, value FROM v$sysmetric WHERE metric_name IN ('PGA Memory MBytes', 'PGA Cache Hit %') AND intsize_csec > 3000;若前者 1 分钟内波动 >20%,后者低于 85%,基本锁定 PGA 级别异常 - 查 OS 内存是否真实吃紧:
free -h看 available 是否 cat /proc/meminfo | grep -E "^(MemAvailable|SwapFree)" 确认是否 swap 已被触发 - 注意 Oracle 的
pga_aggregate_target是软目标,pga_aggregate_limit才是硬限;很多 DBA 调大前者却忘了后者仍卡在默认值(通常是 2×target),导致越调越卡
真正难的不是查出哪条 SQL 在抖,而是区分:是这条 SQL 本身写法缺陷(比如未绑定变量导致大量硬解析),还是底层内存配置与 OS 策略冲突(比如 vm.swappiness=60 加上 Oracle 大页未启用)。这两类问题的修复路径完全相反,混在一起看 ASH 数据只会越查越乱。



















