最准最快定位hw争用对象的方式是解析p3得段头块地址,再查dba_extents确定表或lob段;需先确认实时会话是否真在等hw锁,rac环境须查gv$session_wait;p3需用dbms_utility拆解为file#/block#;segment_type为lobsegment或table,undo表空间则指向回滚段;insert与lob更新根因不同,解法各异;assm下还需排查位图块争用及extent碎片化。

直接看 P3 解析出的段头块位置,再查 dba_extents 定位到具体表和 LOB 段,这是最准、最快的方式。
查实时会话确认是否真在等 HW 锁
别一看到 AWR 里有 enq: HW - contention 就急着调优——先确认当前是不是真卡在这儿。执行:
SELECT sid, serial#, event, p1, p2, p3, sql_id FROM v$session_wait WHERE event = 'enq: HW - contention';
如果返回空,说明只是历史峰值;有记录才需继续追。注意:RAC 环境下要查 v$ges_enqueue_stat 或跨实例 gv$session_wait,否则可能漏掉其他节点的等待。
用 P3 反解出争用对象(关键步骤)
P3 是相对数据块地址(RDBA),它指向段头块,不是数据块本身。必须用 DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE 和 DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK 拆解:
SELECT DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(p3) AS file#,
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(p3) AS block#
FROM v$session_wait
WHERE event = 'enq: HW - contention'
AND ROWNUM = 1;
拿到 file# 和 block# 后,查 dba_extents:
SELECT owner, segment_name, segment_type, tablespace_name FROM dba_extents WHERE file_id = &file_id AND &block_id BETWEEN block_id AND block_id + blocks - 1;
常见结果是:segment_type = 'LOBSEGMENT' 或 'TABLE';若 tablespace_name 是 UNDO,说明争用发生在回滚段扩展,不是业务表本身。
区分是 INSERT 还是 LOB 更新引发的争用
同一个等待事件,根因不同,解法完全不同:
- 如果是高频
INSERT(尤其无索引/全表扫描插入),争用集中在表段 HWM 推进,segment_type显示为TABLE,优先考虑分区或预分配 extent - 如果是
UPDATE或INSERT含大CLOB/BLOB,segment_type多为LOBSEGMENT,且tablespace_name常与主表不同——这时重点看CHUNK大小、RETENTION设置,以及是否启用了DISABLE STORAGE IN ROW - 不要被表结构里有 LOB 字段就默认归因为 LOB —— 实际可能是普通列插入触发 HWM 扩展,LOB 只是“恰好存在”
验证方法:查 v$active_session_history 关联 sql_id,再查 v$sql 的 sql_text,看真实执行的是 INSERT 还是 UPDATE,有没有 /*+ APPEND */。
别跳过 ASSM 位图块这个隐藏瓶颈
即使你定位到某张表,也别急着 ALTER TABLE ... ALLOCATE EXTENT。在 ASSM 表空间中,HW 锁争用常伴随 latch: cache buffers chains 或 latch: segment header 上升——这说明问题不在 HWM 本身,而在 L1/L2 位图块争用。此时:
- 检查
dba_segments中该段的blocks和extents比值,若远低于 64(即平均 extent 很小),说明碎片化严重 - 用
select * from v$segment_statistics where object_name = 'xxx' and statistic_name in ('ITL waits', 'buffer busy waits')辅助判断 - 对高并发插入表,
NEXT_EXTENT设为 8M 或 16M 比默认 64K 有效得多,但前提是表空间未启用autoextend且磁盘充足
真正难处理的,是那种既不能改应用逻辑、又无法停机重建分区的生产表——这时候 P3 解析出的 segment_name 只是起点,后面还得结合 IO 延迟、undo 表空间压力、甚至 _db_block_lru_latches 参数一起看。











