可直接通过v$session_wait关联dba_extents秒级定位io争用段,无需等待awr;关键查state='waiting'且event为db file sequential/scattered read的会话,用p1(file_id)和p2(block_id)精确定位到具体表/索引段,空结果则转向v$segment_statistics查物理读top对象。
直接查 v$session_wait + dba_extents 关联,就能秒级定位到具体段,不需要等 awr 报告。
查正在 WAITING 的 IO 事件并反推段名
高频率 IO 争用一定伴随大量会话处于 db file sequential read 或 db file scattered read 等待状态。关键不是“谁读得多”,而是“谁正在卡住”。执行以下查询(需 DBA 权限):
SELECT event, p1text, p1 AS file_id, p2text, p2 AS block_id,
(SELECT owner || '.' || segment_name
FROM dba_extents
WHERE file_id = p1
AND p2 BETWEEN block_id AND block_id + blocks - 1
AND ROWNUM = 1) AS segment_info
FROM v$session_wait
WHERE event IN ('db file sequential read', 'db file scattered read')
AND state = 'WAITING';
说明:
-
p1是文件 ID,可关联dba_data_files查表空间名 -
p2是块号,结合dba_extents才能落到具体段(表、索引、LOB) - 若
segment_info返回空,说明该块属于临时段、回滚段或未分配空间,需转向v$segment_statistics查物理读 TOP 对象
为什么不能只看 AWR 的 “SQL ordered by Reads”?
AWR 报告里的 SQL ordered by Reads 显示的是历史累计逻辑/物理读,但无法反映“此刻谁在排队”。典型陷阱:
- 一条每天跑一次的报表 SQL,单次读 1000 万块,但当前没在跑 → 它不会出现在
v$session_wait中,却会霸榜 AWR - 一个高频小查询(如订单状态检查),每次只读几块,但并发 200 个会话全卡在同一个索引根块上 →
read by other session暴增,v$session_wait立刻暴露,AWR 却可能不显眼 - 临时表或排序溢出产生的 direct path read,不走 buffer cache,不触发上述等待事件,但真实消耗 IO → 需额外查
v$sql中的direct_writes字段
容易被忽略的热块信号:read by other session
这个事件是 IO 争用的“黄金指标”,它不表示磁盘慢,而表示多个会话反复抢同一块数据(比如小表主键索引根块、序列号生成表的当前值块)。一旦出现:
- 平均等待时间
avg_wait_ms超过 5ms 就值得警惕 - 必须立刻查
dba_extents定位段,再查该段是否缺乏分区、是否索引设计不合理、是否用了无缓存序列(NOCACHE) - 不要急着加磁盘或调 IOPS——问题在访问模式,不在硬件
补充验证:确认是不是真 IO 慢,还是假争用
仅靠 Oracle 层等待事件不够,必须交叉验证 OS 层:
- 运行
iostat -x 1 5,重点看await(毫秒)和%util:若await> 20ms 且%util - 若
await正常(v$session_wait 中db file sequential read大量堆积,基本可断定是热块或 SQL 访问路径问题 - 用
pidstat -d 1确认是oracle进程本身在发 IO,而非备份、归档或外部脚本干扰
真正难处理的从来不是“IO 高”,而是“IO 高得莫名其妙”——比如所有等待都指向一个 2MB 的小表,或者 segment_info 查不到对象。这时候要怀疑是不是隐式转换导致索引失效,或者统计信息严重过期让优化器选了全表扫描。











