AWR是Oracle 10g引入的自动工作负载仓库,每小时采样ASH内存数据并持久化到磁盘,默认保留7天,用于长期性能分析与诊断。

直接查正在等这个事件的活跃会话
别先翻 AWR 报告总时间,AWR 里“Top Events”只告诉你发生了多少次等待,不告诉你是谁在等、等的是哪个块。真正要动手,得从 v$active_session_history(ASH)里捞最近一小时的实时采样:
-
CURRENT_OBJ#是关键字段——它指向实际被读的段对象(可能是索引、表、甚至 undo 段),不是执行计划里写的那个表名 - 如果
object_name为空,说明读的是系统段,这时得用P1(file#)和P2(block#)去查dba_extents - 执行以下语句快速定位高频 SQL 和对象:
SELECT sql_id, current_obj#, object_name, COUNT(*) cnt FROM v$active_session_history a JOIN dba_objects o ON a.current_obj# = o.object_id WHERE event = 'db file sequential read' AND sample_time > SYSDATE - 1/24 GROUP BY sql_id, current_obj#, object_name ORDER BY cnt DESC;
看执行计划里是不是在疯狂回表
绝大多数高 db file sequential read 都卡在 TABLE ACCESS BY INDEX ROWID 这一步。它每次都要根据 ROWID 去磁盘找数据块,如果这些块物理位置分散,就变成大量随机单块读。
- 用
DBMS_XPLAN.DISPLAY_CURSOR('sql_id')查当前执行计划,重点盯INDEX RANGE SCAN后面是否紧跟着TABLE ACCESS BY INDEX ROWID - 对比该操作的
Rows实际值 vs 预估值:差 10 倍以上,基本就是回表读了远超预期的块 - 如果
Cost占总 Cost 70% 以上,或对应表的v$segment_statistics.logical_reads远高于其索引段,回表已成瓶颈
检查索引是否真被用上、顺序是否匹配
索引字段顺序和 WHERE 条件不匹配时,优化器可能退化为全索引扫描(INDEX FULL SCAN 或低效的 INDEX RANGE SCAN),反而加重单块读负担。
- 比如索引是
(salary, dept_id),但 SQL 是WHERE dept_id = ?,那索引基本失效 - 加
/*+ index(t idx_col) */hint 强制走索引没用——优化器仍可能全扫索引叶子块,每块一次db file sequential read - 用
DBA_HIST_SQL_PLAN或v$sql_plan确认实际执行路径,别信开发说“我加了索引”
别急着调 db_cache_size,先确认是不是访问模式问题
加大 buffer cache 对多数 db file sequential read 场景无效。原因很简单:主键查用户档案、按 ID 随机访问小表,每次请求的块地址几乎不重复,缓存再大也留不住。
- 典型现象:
db_cache_size从 4G 拉到 16G,buffer cache hit ratio只从 89% → 91%,等待时间纹丝不动 - 真正有效的是让访问“可预测”:把高频随机访问的小表用
ALTER TABLE ... STORAGE (BUFFER_POOL KEEP)强制 keep 到 keep pool - 或者对冷热不均的索引段,用
ALTER INDEX ... STORAGE (BUFFER_POOL KEEP)固定住关键叶节点
最常被忽略的一点:平均等待时间 time_waited_micro / waits 如果低于 5ms,基本是正常机械盘延迟,问题不在存储,而在 SQL 是否真的需要读这么多块——别被“sequential”字面意思带偏,它指逻辑单块读,不是物理连续读。











