db file scattered read 高不等于性能差,仅当其占总等待超30%且Av Blks/Rd长期低于4时才需干预;须通过v$sql_plan定位全表扫描SQL、结合AWR报告与10046 trace分析根本原因,而非盲目调参。
db file scattered read 高,不等于性能差;但若它占总等待时间 30% 以上、且平均每次读块数(av blks/rd)长期低于 4,才真该动手。
怎么确认是全表扫描在拖慢系统
别只看 v$session_event 里 db file scattered read 的等待时间——它只是现象。关键得定位到具体 SQL 和对象:
- 查当前活跃会话中触发该等待的 SQL:
SELECT sql_id, sql_text FROM v$sqltext t JOIN v$sql_plan p ON t.sql_id = p.sql_id WHERE p.operation = 'TABLE ACCESS' AND p.options = 'FULL' ORDER BY t.piece - 查哪些表被频繁全扫:
SELECT owner, object_name, object_type FROM dba_objects WHERE data_object_id IN (SELECT row_wait_obj# FROM v$session WHERE event = 'db file scattered read') - 看 AWR 报告 “SQL ordered by Gets” 或 “SQL ordered by Reads”,找
buffer_gets/disk_reads极高但执行次数低的语句——大概率是没走索引的报表类 SQL
注意:INDEX FAST FULL SCAN 同样触发 db file scattered read,别漏掉索引本身的问题。
加索引前先问三个问题
不是所有全表扫描都该被索引干掉。盲目建索引可能让 DML 更慢、空间更碎、甚至让优化器选错执行计划:
- 这条 SQL 是否真的需要返回大量数据?比如报表导出、ETL 加载——这时全扫 +
db file scattered read反而是最高效路径 - 谓词字段的选择性是否足够?
WHERE status IN ('A','B')这种低选择性条件,建普通 B-Tree 索引效果有限,反而可能引发更多db file sequential read - 表是否已分区?如果是按时间字段分区的大表,优先考虑
PARTITION PRUNING,比单列索引更治本
验证方法:对目标 SQL 加 /*+ INDEX(t idx_col) */ hint 强制走索引,再对比逻辑读和执行时间——如果 buffer_gets 没降反升,说明索引不合适。
索引建不对,反而加重 scattered read
常见错误包括:
- 建了索引但统计信息过期:
DBMS_STATS.GATHER_TABLE_STATS必须跑,否则优化器仍可能选全扫 - 索引字段顺序和查询条件不匹配:比如
WHERE dept_id = ? AND salary > ?,却建了(salary, dept_id)索引,范围扫描失效 - 索引未包含查询所需列,导致回表:若 SQL 中有
SELECT name, email FROM emp WHERE dept_id = ?,只建(dept_id)索引,就会触发大量db file sequential read回表,整体 I/O 不减反增 - 用了函数或隐式转换:
WHERE UPPER(name) = 'JOHN'或WHERE date_col = TO_DATE('2025-01-01', 'YYYY-MM-DD')会让索引失效,最终退化为全扫
检查方法:看执行计划中 access 和 filter 的区别——filter 表示条件是在取出数据后才过滤,说明索引没覆盖到位。
db_file_multiblock_read_count 不是调优第一选项
这个参数常被误当作“万能加速键”,但它只设上限,不保下限:
- 设成 128,但表段区(extent)大小只有 8 块?那一次最多读 8 块,
p3值永远上不去 - Buffer Cache 已缓存部分块?Oracle 会拆成多次 I/O,其中一些变成
db file sequential read,db file scattered read次数反而变少但单次更小 - Linux 下没启用异步 I/O(
disk_asynch_io=TRUE)或文件系统不支持大块传输?参数再高,OS 层也吞不下
真正该做的:开 10046 trace(level 8),查 WAIT 行里的 p3 值分布。如果多数 p3 是 16 或 32,而你设的是 128,说明瓶颈根本不在参数,而在存储连续性或缓存命中率——这时候调参毫无意义。
最后提醒一句:db file scattered read 是结果,不是病因。盯着等待事件本身调,容易陷入“越调越乱”的陷阱。先抓 SQL,再看执行计划,最后才碰参数——这才是 Oracle I/O 问题的正确解题顺序。

















