DBA_HIST_SEG_STAT本身不争用,问题源于AWR快照写入WRH$_SEG_STAT时的高并发批量插入,可能引发enq: TX或latch争用;需检查快照间隔、段变更频率、采集阈值及业务段真实争用。

查 DBA_HIST_SEG_STAT 是否被高并发写入压垮
DBA_HIST_SEG_STAT 本身不争用,但它的底层基表(如 WRH$_SEG_STAT)在快照采集时会批量插入——若 AWR 快照间隔太短(比如 15 分钟)、又叠加大量段变更(如频繁 DDL、分区交换、LOB 写入),就可能触发 enq: TX - row lock contention 或 latch: cache buffers chains,尤其在 WRH$_SEG_STAT 的主键索引上。
验证方法:从 AWR 报告的 Top 5 Timed Events 中找是否出现以下组合:
-
enq: TX - row lock contention等待时间占比 >1%,且 Wait Class 是 “Application” -
latch: cache buffers chainsAvg Wait > 1ms,且 Waits 数在快照内突增 3 倍以上 - SQL ordered by Parse Calls 里有大量
INSERT INTO wrh$_seg_stat类语句
注意:这些等待不是 DBA_HIST_SEG_STAT 视图查询导致的,而是 AWR 自动采样写入时发生的;所以问题不在“查”,而在“写”。
确认段统计采集是否过度开启
Oracle 默认只对 top-N 活跃段采样,但若手动调大了 _sga_max_size 或启用了隐含参数 _kgl_large_heap_warning_threshold,可能间接导致更多段被纳入监控范围,加剧 WRH$_SEG_STAT 写压力。
检查当前段采集阈值:
SELECT name, value FROM v$parameter WHERE name IN ('_kgl_large_heap_warning_threshold', '_sga_max_size');更直接的方式是查实际采集段数:
SELECT COUNT(*) FROM dba_hist_seg_stat WHERE snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot);
若单次快照记录超 5000 行,且业务并无大规模段变更,说明采集粒度失控。此时应避免手动干预隐含参数,优先检查是否有脚本反复执行 DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO 或误启用 STATISTICS_LEVEL = ALL。
用 DBA_HIST_SEG_STAT 定位真实争用段,而非误判为 AWR 自身问题
很多 DBA 看到 enq: TX 就怀疑是 AWR 写入慢,其实更可能是某个业务段本身存在高并发 DML,而 DBA_HIST_SEG_STAT 只是忠实记录了它——这时该段在报告中会表现为:
-
logical_reads_total或physical_reads_total在多个快照中持续阶梯式上升 -
db_block_changes_total高且与txncount(来自v$undostat)强相关 - 对应
obj#查dba_objects发现是高频更新的订单表或日志表
执行定位语句(替换 &snap_id 为问题快照 ID):
SELECT o.object_name, o.object_type, s.logical_reads_total, s.physical_reads_total FROM dba_hist_seg_stat s JOIN dba_objects o ON s.obj# = o.object_id WHERE s.snap_id = &snap_id ORDER BY s.logical_reads_total DESC FETCH FIRST 5 ROWS ONLY;
如果前 5 名全是 TABLE 类型且 logical_reads_total > 1e7,基本可判定争用源头是业务段,不是 AWR 机制。
避开 DBA_HIST_SEG_STAT 查询引发的 latch 争抢
虽然视图本身只读,但高并发执行 SELECT * FROM dba_hist_seg_stat(尤其没加 snap_id 过滤)会大量扫描基表 WRH$_SEG_STAT,触发 latch: shared pool 和 latch: row cache objects 等争用。
安全查询建议:
- 永远带上
snap_id或时间范围过滤,例如:WHERE snap_id BETWEEN 12345 AND 12346 - 避免
SELECT *,只取必要字段:obj#, dataobj#, logical_reads_total, physical_reads_total - 不要在业务高峰执行全表扫描式查询,可用
DBA_HIST_SEG_STAT_OBJ(按对象聚合)替代原始明细
最易被忽略的一点:DBA_HIST_SEG_STAT 的数据来源是内存中的 V$SEGSTAT 快照,而 V$SEGSTAT 本身受 _kghdsidx_count 控制哈希桶数量——若该隐含参数被调小,即使查询量不大,也会因哈希冲突升高 latch 争抢概率。


















