I/O等待高八成非磁盘慢,而是SQL反复扫描表或索引;需联动AWR中“SQL ordered by Reads”与“File IO Stats”,重点看Physical Reads占比及Avg Read Time,结合执行计划判断是否全表扫描、索引失效或PGA不足导致temp写入。
i/o等待高,八成不是磁盘本身慢,而是sql在反复扫同一张表或索引——awr里sql ordered by reads和file io stats两个章节必须联动看。
查哪个数据文件被读得最多
直接翻AWR报告里的File IO Stats章节(通常在“I/O部分”靠后),重点关注Physical Reads和Avg Read Time (ms)两列:
-
Physical Reads值异常高(比如单个数据文件占全库70%以上),说明IO压力集中在这一个文件上,不是存储整体瓶颈,而是对象分布或SQL访问模式问题 -
Avg Read Time持续>15ms才值得怀疑磁盘响应;若<5ms但Physical Reads爆炸,基本可排除硬件问题,是逻辑层在疯狂读 - 注意
Tablespace列:如果全是USERS或SYSTEM表空间下的文件,大概率是没走索引的全表扫描;如果是TEMP表空间,说明大量排序/哈希操作溢出到磁盘
定位是哪条SQL在狂读
SQL ordered by Reads章节排第一的SQL,往往吃掉全库80%+的物理读。别只看“Reads”数值,重点交叉验证三件事:
- 看
Executions:执行1次就读200万块,和执行1000次每次读2000块,优化优先级完全不同 - 对照
SQL ordered by Elapsed Time:如果同一条SQL也排在耗时榜前列,说明它不仅IO重,执行路径也烂(比如嵌套循环没走索引) - 点开SQL ID查看执行计划:确认是否出现
FULL(全表扫描)或TABLE ACCESS BY INDEX ROWID BATCHED但INDEX RANGE SCAN走了极低效的索引(如选择性差、字段顺序错)
为什么db file sequential read高却不是索引问题?
这个等待事件常被误判为“索引坏了”,其实更可能是以下情况:
- 频繁访问小表的单行数据(比如配置表),但该表没建主键或唯一索引,优化器被迫走全表扫描+
ROWID定位——表面是sequential read,本质是缺失约束 - 大表上有高选择性索引,但查询条件用了函数(如
WHERE UPPER(name) = 'ABC'),导致索引失效,退化为全表扫描+逐行判断 - 绑定变量窥探失效,某次执行用了非典型值,走了错误执行计划,后续被缓存复用,造成大量无效单块读
-
_small_table_threshold参数过小(默认是buffer cache的2%),导致中等大小的表也被强制走direct path read,绕过buffer cache,反而增加物理读
别漏掉temp和undo文件的IO伪装
看到File IO Stats里TEMP或UNDOTBS1文件物理读飙升,别急着加temp表空间,先查根源:
- 查
SQL ordered by Temp Space:确认是不是某条SQL排序/聚合占了巨量PGA,撑爆了内存,被迫写temp - 查
Instance Activity Stats里的sorts (disk)和sorts (memory)比值:若disk占比>5%,说明PGA太小或SQL太暴力 - 查
Undo Segment Stats:如果UNDO文件IO高且伴随snapshot too old报错,大概率是长事务或未提交查询拖住了undo retention
真正卡住I/O的,往往不是磁盘转速或队列深度,而是某条SQL把500万行数据从磁盘拖进内存又吐出去——AWR里Physical Reads和SQL ordered by Reads对不上号的时候,最该盯紧的是执行计划里的Rows预估和实际返回行数是否差三个数量级。


















