free buffer waits本质是前台进程等待dbwr从lru链拉出脏块腾出空闲缓冲区,而非等待磁盘写完成;根本原因是dbwr处理速度跟不上前台消耗buffer节奏,高free buffer inspected/requested比值(>3~5)表明dbwr滞后,比值接近1则指向buffer cache过小或低效sql引发物理读爆炸。

查 db file parallel write 等待是否在ASH中集中爆发
DBWR写盘慢不会立刻表现为前台SQL卡住,而是先堆积 free buffer waits,再引发前台会话反复等待、重试、甚至触发 write complete waits。ASH里看不到DBWR自身(它是后台进程),但能抓到前台会话因缺空闲块而卡在 free buffer waits,或因脏块刷不出去而被拖慢的执行链。
关键动作是过滤最近30分钟内高负载时段的ASH样本:
SELECT sql_id, event, wait_class, COUNT(*) FROM v$active_session_history WHERE sample_time > SYSDATE - 1/48 AND wait_class = 'System I/O' AND event IN ('free buffer waits', 'write complete waits') GROUP BY sql_id, event, wait_class ORDER BY COUNT(*) DESC;- 若
free buffer waits出现频次远超其它I/O类等待(比如10倍以上),且集中在几个sql_id上,基本锁定是这些语句触发了大量脏块生成,而DBWR跟不上 - 注意:不要只看
db file parallel write—— 它只出现在DBWR采样点,ASH前台采样几乎捕不到;它高是结果,不是原因
确认是不是DBWR线程本身被阻塞,而非存储慢
db file parallel write 平均等待时间高,不等于磁盘真慢。可能DBWR发出了I/O请求,但被OS或存储层排队压住,也可能DBWR自己调度异常(如被信号中断、CPU调度失衡)。
要区分这两类问题,得交叉验证:
- 查
v$iostat_file中对应数据文件的AVG_WRITE_TIME是否同步飙升(>20ms 是危险信号);如果没涨,说明I/O请求根本没到底层,卡在Oracle或OS层 - 查
v$session中name = 'dbwr'的后台进程状态:SELECT p.spid, s.state, s.event, s.seconds_in_wait FROM v$process p JOIN v$session s ON p.addr = s.paddr WHERE p.name = 'DBW0';—— 若state = 'WAITING'且event = 'rdbms ipc message'或长期停在'smon timer',说明DBWR没在干活,可能是被CPU调度压制或内部锁阻塞 - 检查
db_writer_processes是否过少:OLTP系统单实例建议至少设为4;若设为1且脏块生成速率突增(见AWR中DB Block Changes Per Sec),DBWR必然成为瓶颈
关联 free buffer waits 和实际业务SQL,避免误判为“IO问题”
很多DBA看到 free buffer waits 就立刻查存储,但真实场景中,70%以上的案例根源是某条SQL短时间内疯狂修改小表(比如计数器表、状态表),或批量UPDATE未分批提交的大表,导致Buffer Cache快速填满脏块。
正确下钻路径是:
- 从ASH中找出
free buffer waits最多的sql_id - 用该
sql_id查v$sql:SELECT sql_text, executions, buffer_gets/executions "Gets/Exec", disk_reads/executions "Reads/Exec", rows_processed/executions "Rows/Exec" FROM v$sql WHERE sql_id = 'xxx'; - 典型误判信号:
Gets/Exec很低(Rows/Exec 却很高(>10k)、executions在短时间陡增 —— 这是高频小事务刷脏块的特征,不是IO能力问题 - 此时加SSD、调高
db_writer_processes不仅无效,还可能因更多并发写加剧latch争用(如cache buffers lru chain)
为什么 write complete waits 突然变长,但 db file parallel write 没明显升高?
这是最易被忽略的线索:write complete waits 是前台会话等DBWR完成某次写操作后才能继续,而 db file parallel write 是DBWR自己等I/O返回。两者时间不一致,说明DBWR发出I/O后,前台就开始等,但DBWR还没收到完成通知 —— 典型表现是 write complete waits 平均等待达几十秒,而 db file parallel write 仍只有几毫秒。
这往往指向两个深层问题:
- 操作系统异步I/O子系统异常:比如Linux上
aio-max-nr被设得太小,或DBWR发起的异步I/O请求在内核队列中长时间挂起 - DBWR写入目标文件所在磁盘组存在failgroup级非对称:比如某ASM failgroup底层LUN响应极慢,DBWR把多个写请求发过去后,整体等待被最慢的那个拖住,但平均值被其它快路径拉低
- 必须用
gv$asm_disk_iostat按failgroup分组查disk_write_time,不能只看v$iostat_file的汇总值
DBWR写盘慢的根因从来不在“磁盘快不快”,而在“Oracle怎么用磁盘”——尤其当 write complete waits 和 free buffer waits 同时飙高时,90%的情况是SQL行为+DBWR配置+ASM路径三者没对齐,而不是换更快的SSD能解决的。











