<p>enq: TX - index contention是索引分裂竞争的核心等待事件,表现为高并发插入时多个会话争抢同一索引块分裂权限,需结合ASH中ON CPU样本、逻辑读暴增及current_obj#关联索引验证定位。</p>

索引分裂本身不报错、不抛异常,但会持续消耗CPU和I/O,ASH里最典型的信号是大量ON CPU样本 + enq: TX - index contention等待 + 对应SQL的逻辑读暴增——这三者同时出现,基本可以锁定是索引分裂在拖慢系统。
查ASH中索引分裂的直接等待事件
Oracle不会把“索引分裂”作为独立等待事件暴露,而是通过事务锁争用体现。关键不是找“split”,而是抓被阻塞的会话链:
-
enq: TX - index contention是索引分裂最核心的等待事件,表示多个会话在争抢同一索引块的分裂权限 - 必须用
gv$active_session_history(RAC环境),否则只看到本节点样本,而分裂热点常集中在某一个实例 - 时间窗口要动态:用
SAMPLE_TIME > SYSDATE - INTERVAL '10' MINUTE,别写死时间字符串,避免因采样精度(.0/.1秒)错过关键样本 - 聚合时加
current_obj#,方便后续关联到具体索引:SELECT current_obj#, event, COUNT(*) cnt FROM gv$active_session_history WHERE event = 'enq: TX - index contention' AND sample_time > SYSDATE - INTERVAL '10' MINUTE GROUP BY current_obj#, event ORDER BY cnt DESC;
确认current_obj#是否真对应活跃索引
仅靠current_obj#查出对象名不够,很多表有多个索引,得验证是不是正在被DML高频访问的那个:
- 先查对象名:
SELECT object_name, object_type FROM dba_objects WHERE object_id = <current_obj#> - 再确认该索引是否处于高更新状态:
SELECT index_name, monitoring FROM dba_indexes WHERE table_name = '<TABLE_NAME>';若monitoring = 'YES',说明近期有大量DML触发索引维护 - 重点看
dba_ind_statistics中leaf_blocks和blevel是否在短时间突增——分裂会导致叶块数快速上涨、树高变大 - 别忽略
v$segment_statistics里的physical writes和logical writes,索引分裂会显著推高这两项
结合SQL执行特征交叉验证
单看等待事件容易误判,必须回溯到SQL行为本身。索引分裂引发的性能下降,往往伴随以下SQL级特征:
- 同一条
sql_id在ASH中大量出现session_state = 'ON CPU'且event为空的样本——说明它真正在做分裂相关的计算(如块扫描、空块探测),不是在等锁 - 该SQL的
v$sql中buffer_gets(逻辑读)远高于executions,比如executions = 1但buffer_gets > 50000,这是典型“一次更新扫遍整个索引分支”的分裂前兆 - 查
v$sql_plan发现执行计划没变,但io_cost或cpu_cost比历史值高出数倍,说明优化器估算失真,实际运行时因分裂导致物理访问路径恶化 - 如果SQL涉及
WHERE条件含序列/时间戳字段(如created_date > SYSDATE - 1),更要警惕——这类高插入率场景最容易触发右边界叶块频繁分裂
避开“failed probes”指标的常见误读
failed probes on index block reclamation这个统计值高,常被当作索引分裂证据,但它反映的是“空块回收失败”,不等于正在分裂。容易踩的坑有:
- 该指标在
dba_hist_sysstat里才有,v$sysstat不实时刷新,查不到最新值 - 值高不一定代表当前有问题:如果系统刚完成大批量
DELETE,但事务未提交,这些块上的事务标记会让后续所有索引分裂都失败探测,此时failed probes飙升,但根源是长事务,不是索引设计 - 真正要盯的是
gv$transaction.used_ublk > 10000的会话——它占用undo段超过80MB,极大概率是那个卡住索引分裂的“源头事务” - 别只看单个索引,用
dba_indexes查logging = 'NO'的索引,非记录日志索引在分裂时跳过redo生成,反而更容易因崩溃导致块损坏,加剧分裂延迟
索引分裂的问题难在它不报错、不中断业务,但会悄无声息地把I/O和CPU拖进深水区。最有效的定位方式,永远是把ASH中的等待事件、SQL级资源消耗、底层段统计三者对齐——缺一不可。尤其注意RAC环境下分裂热点可能只落在单节点,跨节点查gv$视图是硬性要求。



















