buffer busy waits 本质是 cbc latch 与 buffer pin 协同失效导致的缓冲区争用,在 rac 和高并发 oltp 中易成吞吐瓶颈,根源常在索引热点、assm hwm 争用或跨实例 gc 等待。
buffer busy waits 直接反映 buffer header(bh)或 buffer 本体的访问冲突,不是锁等待,而是“抢不到缓冲区”——这在 rac 和高并发 oltp 场景下会迅速放大成吞吐瓶颈。
Buffer Busy Waits 的本质是 CBC Latch + Buffer Pin 锁协同失效
Oracle 访问块前必须完成两步关键操作:先持 CBC Latch 搜索 hash chain 找到对应 BH,再把该 BH 的 Buffer Pin 状态设为 S(读)或 X(写)。这两步都需独占持有 CBC Latch(哪怕只是读),而 Buffer Pin 锁本身又不能跨实例共享。
常见卡点包括:
- 多个会话同时请求同一 block(如索引叶块、序列主键插入热点页),
BH被一个会话以 X 模式 pin 住,其余会话只能等 - RAC 环境下,
gc current block busy或gc buffer busy acquire实际是远程实例尚未完成 pin 操作,本地实例反复重试获取BH,表现为持续等待 - ASSM 表空间中高水位线(HWM)附近空闲块少,大量 INSERT 争抢少数可插入块,
Buffer Pin冲突集中爆发
AWR 中看到高 Buffer Busy Waits 时,别只盯 object_name
AWR 的 Segments by Buffer Busy Waits 列表容易误导人——它只显示被争用的 segment,但真正瓶颈往往在索引结构上。比如:
- 主键用
seq.nextval插入,导致右边界索引叶块频繁分裂,所有新插入都挤在同一个 block 上 - 未分区的大表,全局索引更新引发跨 block 的
Buffer Pin链式等待 - 索引高度 > 4,每次查找都要 traversing 多层 BH,CBC Latch 持有时间拉长,冲突概率指数上升
验证方式:select owner, object_name, subobject_name, statistic_name, value from gv$segment_statistics where statistic_name = 'buffer busy waits' and value > 5000 order by value desc;,再结合 dba_indexes 查对应索引的 blevel 和分区状态。
gc buffer busy acquire 在 RAC 中的特殊放大效应
RAC 不是简单加机器就能线性扩容,并发性能反而可能因 GC 协议开销陡降。当 gc buffer busy acquire 占 AWR Top 10 Foreground Events 超过 5%,基本可判定存在跨实例 buffer 争用:
-
gv$sysstat中gc current blocks received增速远高于gc cr blocks received,说明大量当前模式块被跨实例传输,而非一致性读块 - ASH 中按
inst_id, current_obj#, sql_id聚合,常能定位到同一条 SQL(如SQL_ID 25gcvqkbjt7jd)在多个实例上反复争用同一 object_id - 这不是 SQL 写得差,而是数据分布 / 索引设计 / 序列使用方式与 RAC 的 cache fusion 机制天然互斥
真正难处理的是那种「单条 SQL 看似合理、执行计划干净、但一并发就卡死」的情况——此时 Buffer Busy Waits 往往已混在 gc current block busy、latch: cache buffers chains、enq: TX - row lock contention 多种等待里,需要联合 gv$bh(查 pin 状态)、gv$lock(查 blocker)、gv$session_wait_history(看最近 10 次等待)交叉印证。不拆开看 BH 和 pin 状态,光靠 AWR 报告只会反复优化错方向。











