DELETE后索引段不释放空间,因B树索引仅标记键值为逻辑删除,空闲叶子块不自动回收;重建(REBUILD)可彻底释放空间,而COALESCE效果有限。
为什么DELETE后索引段不释放空间
oracle中执行delete语句删掉大量数据,表段的高水位线(hwm)不会下降,索引叶子块里的键值被标记为“逻辑删除”,但物理块仍保留在段中——dba_segments查出来的索引大小完全不变。这不是bug,是b树索引的设计特性:空闲空间只在后续插入相同键范围时才可能复用,而实际业务中键值分布往往不连续,导致碎片长期淤积。
- 常见错误现象:
SELECT COUNT(*) FROM t返回几万行,但SELECT bytes/1048576 FROM dba_segments WHERE segment_name = 'IDX_T_COL'显示该索引仍占40GB - 根本原因不是“没清干净”,而是索引结构本身产生分裂(Leaf Split)和空洞(Empty Leaf Blocks),这些块无法被自动合并或回收
- 与表不同,索引没有
SHRINK SPACE语法;ALTER INDEX ... COALESCE只能合并相邻叶块,对严重碎片无效
Alter Index Rebuild能真正释放空间吗
能,而且效果通常非常显著——前提是操作正确。重建会抛弃旧索引结构,从头构建一棵紧凑、连续的新B树,把所有有效键值重排填充,彻底丢弃空块和过期分支节点。实测案例中,一个78GB的索引REBUILD后缩到10GB,压缩比达7.2倍。
- 必须显式指定
TABLESPACE和STORAGE参数,否则新索引可能落在默认表空间,且初始区大小沿用旧值,浪费空间 - 加
NOLOGGING可提速并减少日志量,但要求数据库处于归档模式且能接受丢失该操作的恢复能力 - 大索引建议加
PARALLEL 4,但结束后务必执行ALTER INDEX idx_name NOPARALLEL,否则后续DML可能意外并行化拖慢系统 - 不要用
DROP + CREATE代替REBUILD:前者锁表时间更长,且中间存在索引不可用窗口,应用查询直接报ORA-01502
Rebuild Online和普通Rebuild的区别在哪
核心差异在DML可用性与系统开销。REBUILD全程锁索引(非锁表),期间对该索引的SELECT仍可走索引,但所有INSERT/UPDATE/DELETE会被阻塞;REBUILD ONLINE则允许DML并发执行,代价是生成一张临时IOT日志表SYS_JOURNAL_*,记录重建过程中的变更,并在最后原子切换。
- 若业务不能停写,必须选
ONLINE;但要注意它需要额外约20%的空间存放日志表,且重建时间通常比普通模式长1.5–2倍 -
ONLINE模式下,索引状态会短暂变为UNUSABLE(仅在切换瞬间),应用几乎无感;而普通REBUILD期间状态一直是VALID,但DML被挂起 - 分区索引需对每个分区单独执行
REBUILD PARTITION p_name ONLINE,不能直接REBUILD ONLINE整张索引(除非是全局索引) - 重建完成后,记得收集统计信息:
EXEC DBMS_STATS.GATHER_INDEX_STATS('OWNER', 'IDX_NAME');,否则优化器可能继续用旧的低效执行计划
哪些索引其实没必要Rebuild
不是所有“看起来大”的索引都值得重建。盲目定期跑REBUILD脚本反而增加IO压力、日志量和维护窗口风险。先查碎片率再动手:
- 用
ANALYZE INDEX idx_name VALIDATE STRUCTURE后查INDEX_STATS视图,重点关注DEL_LF_ROWS/LF_ROWS比值 > 20% 或HEIGHT > 4才算高碎片 - 群集因子(
CLUSTERING_FACTOR)高的索引,重建不会改善性能——它反映的是表数据物理排序与索引键顺序的匹配度,只能靠MOVE或SHRINK重组表来解决 - 函数索引、域索引、XMLIndex等特殊类型,
REBUILD行为不标准,需查对应文档;SecureFile LOB上的索引也不适用常规重建逻辑 - 如果索引所在表刚做过
MOVE,别急着重建——MOVE已让ROWID全变,索引必然UNUSABLE,此时REBUILD是必须步骤,不是“可选优化”
dba_segments里字节数降了,得跑一次真实业务SQL的EXPLAIN PLAN,确认执行计划没退化、逻辑读是否下降。否则你只是把碎片换了个地方存。











