必须先查p3值定位块类型:p3=1为数据块热、p3=4为段头争用(应迁assm)、p3=17/18为undo资源紧张(需扩容undo表空间)、p3=130表示块正被其他会话读入缓存。
先看p3值再动手,别调db_cache_size
buffer busy waits不是缓存不够大导致的,盲目加大db_cache_size几乎没用,反而可能加剧cache buffers chains latch争用。关键第一步是查p3(即class#),它直接告诉你争的是哪类块:
-
P3 = 1:普通数据块,常见于升序主键INSERT、小表全扫 -
P3 = 4:段头块,基本可断定是MSSM表空间下FREELIST争用 -
P3 = 17或18:UNDO段头或UNDO块紧张,要扩容UNDO表空间,不是调UNDO_RETENTION -
P3 = 130:块不在buffer cache,正被其他会话从磁盘读入——本质是I/O瓶颈暴露为buffer wait
执行这条语句快速抓当前热点:
SELECT p1 AS file#, p2 AS block#, p3 AS class#, COUNT(*) cnt FROM v$session_wait WHERE event = 'buffer busy waits' GROUP BY p1, p2, p3 ORDER BY cnt DESC FETCH FIRST 5 ROWS ONLY;
定位到块后,立刻查所属对象
拿到file#和block#后,不能靠猜,必须用dba_extents精确反查段名。一个块只属于一个extent,但可能跨分区,所以查询必须带partition_name判断:
SELECT s.segment_name, s.partition_name, s.segment_type FROM dba_extents s WHERE &block# BETWEEN s.block_id AND (s.block_id + s.blocks - 1) AND s.file_id = &file#;
注意:current_obj# = 0不等于没对象——可能是刚进入逻辑读阶段还没绑定段,此时更要盯紧current_file#和current_block#;如果查不到结果,说明该块属于临时段、回滚段或UNDO块,得转向dba_rollback_segs或v$rollstat。
按P3类型分路径处理,别一招鲜吃遍天
不同P3值对应完全不同的根因和动作,混用方案会白忙:
-
P3 = 4(段头争用):确认表空间是否为ASSM——查dba_tablespaces中segment_space_management。若为MANUAL,不要ALTER TABLESPACE,需导出→新建ASSM表空间→导入,并指定SEGMENT SPACE MANAGEMENT AUTO -
P3 = 1(数据块热):索引叶块热就用REVERSE KEY或HASH分区索引(如CREATE INDEX i ON t(id) GLOBAL PARTITION BY HASH(id) PARTITIONS 8);小表热就加PCTFREE分散行密度,但DML和SELECT混合场景下,高PCTFREE可能增加latch争用,务必实测 -
P3 = 130:优先优化SQL减少物理读,而不是加buffer cache。查ASH里是否伴随大量db file sequential read,是则说明SQL在扫冷数据,建索引或改写才是正解
容易被忽略的RAC与UNDO细节
RAC环境下buffer busy waits常伪装成gc buffer busy acquire,这时要查Interconnect Ping Latency Stats,延迟高就不是SQL问题;UNDO类争用(P3 = 17/18)必须扩容UNDO表空间,UNDO_RETENTION调再大也没用——因为争的是段头或块本身,不是保留时间。另外,read by other session和buffer busy waits经常共生,但前者是I/O等待的“症状”,后者是内存结构冲突的“病灶”,诊断时必须分开归因。











