段延迟非AWR原生指标,因其仅按文件或表空间聚合I/O延迟,不记录对象名;需通过dba_hist_filestatxs与dba_extents关联反推,并注意单位换算、除零防护及时间过滤。

段延迟(Segment-Level Latency)不是AWR原生指标,AWR不直接统计“某张表或索引的读延迟”,它只聚合到文件、表空间或等待事件层级。想定位段级I/O毛刺,必须绕过AWR的默认视图,用dba_hist_filestatxs反向推算,再关联段对象。
为什么AWR里找不到“段延迟”这个字段
AWR报告中所有I/O延迟都按物理文件(file#)或表空间(tablespace_name)聚合,db file sequential read等事件本身不携带对象名。段(如表、索引)是逻辑结构,其数据块可能分散在多个数据文件中,AWR不做跨文件归因。直接在AWR UI里搜“segment latency”或“table io ms”会一无所获。
- 等待事件统计的是“发生了多少次等待”,不是“哪个段触发了它”
-
Tablespace IO Stats只给平均读写毫秒,无法区分是大表全扫还是小索引随机访问拖慢的 - 即使
db file scattered read占比高,你也无法从AWR里看出是SALES_ORDER还是CUSTOMER_DIM在被扫描
如何用AWR历史视图反推段级I/O延迟
核心思路:先从dba_hist_filestatxs算出每个数据文件的单次I/O耗时,再用dba_extents把文件号+块号范围映射到具体段。关键点在于单位换算和NULL防护:
-
readtim单位是百分之一秒(centiseconds),不是毫秒;需乘以10才得毫秒值 - 必须用
NULLIF(phyrds, 0)防止除零错误,否则查询直接报错 - 时间范围过滤不可省——不加
BETWEEN SYSDATE-7 AND SYSDATE,默认查全库历史,性能极差且结果失真
SELECT /*+ leading(f e) use_hash(e) */
e.segment_name,
e.segment_type,
ROUND((f.readtim * 10 / NULLIF(f.phyrds, 0)), 2) AS avg_read_ms
FROM dba_hist_filestatxs f
JOIN dba_extents e
ON f.file# = e.file_id
AND e.block_id <= f.minblock
AND e.block_id + e.blocks > f.minblock
WHERE f.snap_id IN (SELECT snap_id FROM dba_hist_snapshot
WHERE begin_interval_time BETWEEN SYSDATE-1 AND SYSDATE)
AND f.phyrds > 0
ORDER BY avg_read_ms DESC
FETCH FIRST 10 ROWS ONLY;段延迟高≠段有问题,要排除三类干扰
算出某张表平均读延迟达45ms,别急着重建索引。先确认是否属于以下情况:
- 该段是只读历史分区,但被误加入OLTP查询路径(检查执行计划中
TABLE ACCESS FULL是否命中非活跃分区) - 应用层用了
/*+ FULL(t) */提示强制全表扫描,而该表实际有可用索引 - 该段所在数据文件被其他高IO负载进程(如RMAN备份、Data Pump导入)独占,导致瞬时排队——此时
v$iostat_file实时视图比AWR更准
真正影响性能的是“段延迟 × 访问频次”组合
单次延迟100ms的索引查找,如果每秒只发生5次,对整体DB Time贡献微乎其微;但单次延迟8ms的ORDERS_PK索引,若每秒被访问2万次,累积等待就超过160秒/分钟。AWR的SQL ordered by Physical Reads能暴露高频访问段,但必须手动关联到dba_objects才能确认对象名:
- 从
SQL Statistics页找到Physical Reads Per Exec高的SQL - 用
dbms_xplan.display_awr(<code>sql_id)查执行计划,定位OBJECT_NAME列 - 再查
dba_segments确认该对象是否在高延迟文件上
段延迟本身只是症状,背后往往是统计信息陈旧、绑定变量缺失导致基数估算偏差、或存储层LUN配置不当——AWR给不出根因,只提供第一个可验证的怀疑对象。



















