oracle中索引叶块分裂可通过analyze index validate structure后查询index_stats视图判断,关键指标包括del_lf_rows_len/lf_rows_len>20%、blks_gets_per_access异常偏高,以及blocks只增不减但空闲空间未被复用等痕迹。
怎么查当前索引有没有发生过叶块分裂?
oracle 不直接记录“某次分裂发生于何时”,但分裂会在索引结构中留下可观察痕迹:叶块空闲空间减少、del_lf_rows(已删除但未清理的叶行)堆积、lf_rows_len与blocks比值异常偏低。最轻量级的验证方式是执行 analyze index ... validate structure,然后立刻查 index_stats 视图——注意这个操作会锁表,不能在业务高峰期跑。
关键指标看这两个:
-
(DEL_LF_ROWS_LEN / LF_ROWS_LEN) * 100> 20%,说明大量删除后空间没重用,物理上存在“孔洞” -
BLKS_GETS_PER_ACCESS明显高于同类索引(比如 > 5),意味着每次访问要读更多块,常因分裂后叶块物理不连续导致
90-10分裂和50-50分裂对空间利用率的影响差异
90-10分裂(常见于递增主键+序列插入)会让原叶块长期保持高填充率,新块初始很空;而50-50分裂(随机更新/并发插入)会把数据均分到两个块,短期看更“匀”,但容易造成后续多次小分裂——尤其当块里ITL槽不足或有未提交事务时。
真正影响空间效率的是分裂后的**空闲空间是否能被后续插入复用**:
- 90-10分裂后,新右块空闲多,但若后续仍是递增写入,它很快被填满,复用率高
- 50-50分裂后,两个块都留有中等空闲空间,但若插入键值分布杂乱,可能两边都频繁触发下一次分裂,形成“碎块链”
- 无论哪种,只要发生过分裂,
BLOCKS数就只增不减,哪怕里面很多是空的
为什么DBA_INDEXES.BLEVEL没变,但扫描变慢了?
因为叶块分裂不改变树高,只增加同层块数。但逻辑读变多:一个范围扫描原本顺序读 10 个连续叶块,分裂后可能跳着读 15 个物理分散的块——尤其是 RAC 环境下,gc current block 2-way 或 gc cr block busy 等待会明显上升。
这时候单看 BLEVEL 没用,得结合 AWR 报告里的:
- “Index Fast Full Scan” 的物理读/逻辑读比率
- “Index Range Scan”的平均
buffer gets per execution - 等待事件里有没有
enq: TX - index contention或buffer busy waits(典型右侧热点分裂信号)
重建索引前必须确认的三件事
ALTER INDEX ... REBUILD 能清掉分裂碎片,但代价不小。执行前务必确认:
- 该索引是否被频繁 DML 访问?如果是,优先考虑
ALTER INDEX ... COALESCE(只合并相邻叶块,不重建结构,不锁全索引) - 业务能否容忍短时不可用?
REBUILD ONLINE在 12c 可用,但会生成大量 redo,且要求临时表空间充足 - 统计信息是否要同步更新?加
COMPUTE STATISTICS避免 CBO 用旧基数误判,但会延长执行时间
真正难处理的不是分裂本身,而是分裂后那些“看不见”的空块——它们仍计入 BLOCKS,仍被 INDEX FAST FULL SCAN 扫描,却什么数据也不返回。这种空间浪费在大表索引上最容易被忽略。











