db file scattered read 是sql执行路径失控的明确提示,而非i/o硬件瓶颈;90%以上源于无节制的全表扫描或索引快速全扫描,应优先通过v$sql_plan定位问题sql,再检查统计信息、加索引或重写sql调优。

这不是I/O硬件瓶颈的默认信号,而是SQL执行路径失控的明确提示。 出现严重 db file scattered read 等待,90% 以上的情况是全表扫描(FTS)或索引快速全扫描(IFFS)在无节制地执行——不是磁盘慢,是SQL在反复“掀桌子找东西”。
查哪条SQL正在发起大量分散读
别先看IO吞吐率或磁盘队列,直接定位源头SQL。Oracle 12c 的 v$sql_plan 和 v$sql 联合查询最可靠:
SELECT sql_id, sql_text FROM v$sqltext t JOIN v$sql_plan p USING (sql_id) WHERE p.operation = 'TABLE ACCESS' AND p.options = 'FULL' ORDER BY t.piece;SELECT sql_id, sql_text FROM v$sqltext t JOIN v$sql_plan p USING (sql_id) WHERE p.operation = 'INDEX' AND p.options = 'FULL SCAN' ORDER BY t.piece;
注意过滤掉 sys、system 用户的字典查询(如 v$ 视图访问),它们天然带FTS但不构成问题。重点盯住应用用户(如 app_user、erp)的长SQL或高频短SQL。
为什么12c更容易暴露这个问题
Oracle 12c 默认启用自适应执行计划和动态统计(optimizer_adaptive_statistics=TRUE),但当表统计信息陈旧或列直方图缺失时,优化器可能误判选择性,强行放弃索引走FTS——尤其在谓词含函数、绑定变量窥探失效、或使用 LIKE '%xxx' 场景下:
- 执行
EXPLAIN PLAN FOR ...后查PLAN_TABLE,确认实际执行计划是否真用了FULL或FULL SCAN - 检查对应表的
LAST_ANALYZED时间:SELECT owner, table_name, last_analyzed, num_rows FROM dba_tables WHERE table_name = 'YOUR_TABLE'; - 若
num_rows为 0 或远低于实际,说明统计信息失效,dbms_stats.gather_table_stats必须立即运行
DB_FILE_MULTIBLOCK_READ_COUNT 不是调优起点
这个参数控制每次多块读最多读多少块(默认值通常为 128),但它只影响单次I/O吞吐量,不改变“要不要扫全表”的逻辑。盲目调大反而可能加剧内存压力和LRU链争用:
- 该参数在 12c+ 已自动适配:未显式设置时,Oracle 根据底层存储最大IO能力推导出合理值(如 SSD 上常为 128,HDD 上可能为 32)
- 修改它无法让一条本该走索引的SQL变快;只会让错误的FTS“跑得更起劲”
- 真正有效的干预点只有三个:
加索引、重写SQL避免隐式转换、分区裁剪
最容易被忽略的是:db file scattered read 的 P2(block#)和 P3(blocks)能直接定位到物理热点段,但多数人只盯着等待时间排序,却没用 dba_extents 反查出具体是哪个表或索引在被狂扫——这一步跳过,等于在黑暗里修车。











