必须立刻查v$session定位热点块,执行select sid, sql_id, p1 "file#", p2 "block#", p3 "class#" from v$session where event = 'read by other session',观察p2是否高度集中;若集中则锁定争用对象,用dba_extents按block_id区间匹配段名,避免错用object_id关联。

这不是I/O慢,是多个会话抢同一块缓存加载权——必须立刻抓活会话定位热点块,而不是翻AWR报告。
怎么快速定位正在争抢的file#和block#
AWR里“累计等待时间最长”容易误导,因为read by other session是瞬时争用,汇总后看不出集中性。最有效动作是查当前活跃会话:
- 执行
SELECT sid, sql_id, p1 "file#", p2 "block#", p3 "class#" FROM v$session WHERE event = 'read by other session' - 重点看
p2(逻辑块号)是否高度集中:比如 80% 以上都落在file#=5, block#=123456 - 若分散,大概率是多个不同 SQL 同时全表扫描;若集中,基本锁定某张表/索引的物理块争用
如何安全反查争用对象(别错关联data_object_id)
p1 和 p2 是唯一可信线索,但直接用 dba_objects.object_id 关联会出错——X$BH.obj 对应的是 data_object_id,不是 object_id。
- 安全写法:
SELECT owner, segment_name, segment_type FROM dba_extents WHERE file_id = &FILE_ID AND &BLOCK_ID BETWEEN block_id AND block_id + blocks - 1 - 如果返回为空:该块可能属于 undo、temp、已 drop 未清理的对象,或存在坏块,需查
v$database_block_corruption - 更准方式(需有权限):
SELECT o.owner, o.object_name, o.object_type FROM x$bh b, dba_objects o WHERE b.obj = o.data_object_id AND b.file# = &FILE_ID AND b.dbablk = &BLOCK_ID
怎么判断是scattered read还是sequential read引发的争用
read by other session 几乎总是伴随 db file scattered read 或 db file sequential read,但优化方向完全不同:
- 若伴随大量
db file scattered read:说明是全表扫描或 fast full index scan 触发的多块预读 → 检查统计信息是否过期、SQL 是否缺失谓词、是否该加索引 - 若伴随大量
db file sequential read:更可能是索引唯一扫描或回表卡在热点索引块(如状态字段严重倾斜的 B-Tree 索引根块)→ 优先看dbms_xplan.display_cursor('&sql_id', NULL, 'ALLSTATS LAST')中STARTS和Buffers列,确认是否同一 SQL 并发执行多次 - 特别注意分区表:某分区(如
part_202504)统计信息仍为 0 行但实际已有数十万数据,会导致优化器误判
为什么收集统计信息后问题还在
90% 的 read by other session 根源是执行计划错误,而统计信息只是诱因之一。即使刚收集完,也可能踩这些坑:
- 用了绑定变量窥探(bind peeking),第一次硬解析时传入的值导致计划固化在低效路径上
- 分区表个别分区没被纳入
DBMS_STATS.GATHER_TABLE_STATS范围,granularity => 'ALL'不等于“所有分区都扫了” - 应用层高频轮询同一条 SQL(比如每秒调用几十次),即使执行计划最优,也会反复争同一组块
- 索引设计本身有问题:比如在高并发更新的状态字段上建普通 B-Tree 索引,根块天然成为热块
真正难处理的,是那种看似分散实则集中在几个小索引块上的争用——它不触发 AWR 明显告警,却让响应时间毛刺不断,得靠 v$session_wait 实时抓取 + x$bh 验证才能揪出来。











