直接查v$active_session_history并结合current_obj#、file#和采样时间窗口才能准确定位db file sequential read的真实瓶颈点,否则仅见高等待次数而非问题源头。

直接查 v$active_session_history 就能定位 db file sequential read 的真实瓶颈点,但必须结合 current_obj#、file# 和采样时间窗口过滤,否则看到的只是“高等待次数”,不是“问题源头”。
为什么只看 AWR 里的 Top Events 会误判
AWR 报告中 db file sequential read 排第一,只说明“单块读等待总时间长”,不等于“磁盘慢”或“SQL 写得差”。它可能来自:
- 高频访问小表的主键(逻辑合理,但 buffer cache 没法有效缓存离散块)
- 索引叶节点分裂后物理块分散,每次
read()都触发磁盘寻道 - 执行计划漂移导致原本走全表扫的 SQL 改走索引回表,
current_obj#指向的是索引而非原表 -
object_name为空——实际在读 undo segment 或 temp segment,和业务 SQL 表名完全无关
用 ASH 查具体 SQL 和对象的正确写法
关键不是统计总次数,而是按 sample_time 聚合、绑定 current_obj# 并关联 dba_objects。示例语句必须带时间约束和 session_type = 'FOREGROUND':
SELECT sql_id, current_obj#, o.object_name, COUNT(*) cnt FROM v$active_session_history ash JOIN dba_objects o ON ash.current_obj# = o.object_id WHERE event = 'db file sequential read' AND sample_time > SYSDATE - 1/24 AND session_type = 'FOREGROUND' GROUP BY sql_id, current_obj#, o.object_name ORDER BY cnt DESC;
注意:
-
current_obj#是运行时真实被读的段 ID,比v$sql_plan.object_name可靠得多 - 如果
o.object_name为NULL,用SELECT * FROM dba_extents WHERE file_id = <p1> AND <p2> BETWEEN block_id AND block_id + blocks - 1</p2></p1>反查物理位置 - 不要漏掉
AND session_type = 'FOREGROUND',后台进程(如 DBWn)的db file sequential read属于维护行为,和业务响应无关
识别是否真要优化存储或加缓存
平均等待时间才是判断 I/O 子系统是否异常的硬指标,不是等待次数:
- 用
time_waited_micro / waits算出平均单次等待微秒数;超过 10000(即 10ms)才需怀疑存储响应能力 - 低于 5000(5ms)基本是机械盘正常延迟,优化方向应是减少读次数,而不是换 SSD
- 若
AVG_READ_TIME在v$iostat_file中同步突增,且其他库共用同一存储也出现类似模式,才能锁定网络或阵列层抖动 - 加大
db_cache_size对随机单块读收益极低——buffer cache 本质是 LRU,刚缓存的块下一秒就被踢出,无效扩容反而增加 LRU 链管理开销
容易被忽略的采样精度陷阱
v$active_session_history 默认每秒采样一次,但不是精确到毫秒级快照。连续多次 db file sequential read 可能被压缩成一条记录,wait_time 字段为 0 表示“未完成即被采样”,不代表瞬时完成:
- 看到
WAIT_TIME = 0且event = 'db file sequential read',说明该次读尚未返回,实际耗时 ≥ 1 秒(采样间隔) - 不要用
MIN(wait_time)或MAX(wait_time)做统计,它们在 ASH 中无业务意义 - 真正反映压力的是单位时间内的采样行数(即
COUNT(*)),不是单条记录的wait_time











