应查询v$active_session_history或dba_hist_active_sess_history,过滤enq: tx - index contention等索引相关等待事件,结合current_obj#、sql_id及时间范围定位分裂索引。
直接查 ash 里谁在等索引分裂
索引分裂本身不直接暴露为一个“等待事件”,但它的副作用会体现在 enq: tx - index contention 和 latch: cache buffers chains 等等待上。真正能定位到分裂行为的,是结合 v$active_session_history(即 ash)中 event、sql_id、session_state 和 top_level_sql_id 综合判断。
最有效的起点是过滤出高频率出现的索引相关等待:
-
enq: TX - index contention:说明多个会话正争抢同一个正在分裂的叶子块 -
latch: cache buffers chains(配合P1TEXT = 'file#' and P2TEXT = 'block#'):可能指向热点索引块的缓冲区争用 -
db file sequential read或db file scattered read配合高SQL_ID的 INSERT/UPDATE,暗示分裂后引发的额外 I/O
别只盯着 EVENT 列;要关联 CURRENT_OBJ# 查出对象名,再用 DBA_OBJECTS.OBJECT_NAME 反查是不是索引所属表——很多 DBA 忘了这步,结果把等待归到表上,其实根子在索引。
用 ASH 定位具体是哪个索引在分裂
关键不是“有没有分裂”,而是“哪个索引块在频繁分裂”。靠 ASH 中的 CURRENT_FILE# 和 CURRENT_BLOCK# 能反推出物理块位置,再结合 DBA_EXTENTS 和 DBA_INDEXES 定位到索引段。
常用查询逻辑如下(注意替换时间范围):
SELECT o.object_name, o.object_type, COUNT(*) cnt FROM v$active_session_history h JOIN dba_objects o ON h.current_obj# = o.object_id WHERE h.event = 'enq: TX - index contention' AND h.sample_time > SYSDATE - 1/24 GROUP BY o.object_name, o.object_type ORDER BY cnt DESC;
如果 object_type 是 INDEX,基本可确认问题索引;如果是 TABLE,得继续查该表上的主键/唯一索引是否用了 SEQUENCE 或单调递增字段——这是分裂高发的典型模式。
容易踩的坑:
使用一条命令部署ProbeChain Rydberg测试网代理节点。自动注册为Agent(NodeType=1),免gas,支持macOS/Linux/Windows。触发词:/r
-
CURRENT_OBJ#在非 DML 场景下可能为空或为 0,此时要靠SQL_ID关联V$SQL查绑定变量和执行计划 - RAC 环境下必须加
INST_ID过滤,否则会漏掉其他实例的样本 -
ASH默认只保留 1 小时(取决于_ASH_DISK_WRITE_THRESHOLD),长时间趋势需用 AWR 或手动采样落盘
区分 90-10 Split 和 50-50 Split 的实际影响
V$SYSSTAT 里的 leaf node 90-10 splits 和 leaf node splits 差值,才是真实 50-50 分裂次数。但这两个指标是累积值,无法回溯到具体时间点或 SQL。
真正有用的是结合 ASH + DBA_HIST_SEG_STAT(AWR)看分裂高发时段的段级统计:
- 90-10 Split 多:说明插入集中在索引最右端(如
id NUMBER DEFAULT seq.NEXTVAL),分裂开销小但易造成右侧热点 - 50-50 Split 多:说明插入位置分散(如更新导致键值变大、或随机插入),分裂更重,I/O 和锁持有时间更长
一个简单验证方式:查对应索引的 PCTFREE 设置。若为 0 或 5,且字段是单调递增,基本就是 90-10 主导;若 PCTFREE ≥ 10 且仍有大量 50-50,大概率是并发更新触发 ITL 不足,而非单纯插入。
为什么只看 ASH 不够,还得配 DBA_HIST_ACTIVE_SESS_HISTORY
V$ACTIVE_SESSION_HISTORY 是内存视图,重启或压力大时会被覆盖;而历史分析必须依赖 DBA_HIST_ACTIVE_SESS_HISTORY(即 AWR 中的 ASH 快照)。两者结构一致,但后者有完整时间锚点和压缩存储。
典型误操作:
- 用
V$ASH查昨天的问题,结果返回空——忘了它只存最近几十分钟 - 没加
SNAP_ID条件,在DBA_HIST_ACTIVE_SESS_HISTORY上全表扫,性能极差 - 忽略
SESSION_SERIAL#,把不同会话的同名 SQL 混在一起统计
真正稳定的分析链路是:DBA_HIST_ACTIVE_SESS_HISTORY 定位时间段 → 提取高频 SQL_ID → 关联 DBA_HIST_SQLSTAT 看执行次数与逻辑读 → 再反查该 SQL 涉及的索引结构与字段生成逻辑。分裂从来不是孤立事件,而是业务写法+索引设计+参数配置共同作用的结果。










