先提炼一个核心结论:Oracle 对 MERGE PARTITIONS 操作默认不会维护全局索引——因为合并过程中数据块物理位置被重写,原有索引条目指向旧分区的 ROWID 全部失效,而 B-tree 结构无法局部验证这些条目是否仍然有效,因此索性直接全部标记为 UNUSABLE。本地索引则无需担心:每个分区索引段相互独立,MERGE 只是删除两个旧分区的索引段,再新建一个对应新区间的索引段,其余分区索引照常可用。
ALTER TABLE MERGE PARTITIONS 后全局索引变为 UNUSABLE 的根本原因
Oracle 的 merge partitions 操作默认不维护全局索引(global),这一设计其实有其合理性。合并分区会物理重写数据块的位置,原有索引条目里的 ROWID 指向的地址已经失效。更关键的是,B-tree 索引无法只验证一部分节点是否有效——要么全对,要么全错。与其返回错误结果或处于半死不活的状态,Oracle 选择直接将整个全局索引置为 UNUSABLE,至少保证查询不会读到错误数据。

本地索引(LOCAL)之所以不受影响,是因为每个分区索引段相互独立。MERGE 时直接删除被合并的两个分区索引段,再新建一个对应新区间的索引段,其他分区的索引纹丝不动,自然不需要整体重建。
MERGE PARTITIONS 必须加 UPDATE GLOBAL INDEXES 才能避免失效
UPDATE GLOBAL INDEXES 可不是什么可选参数,它是防止索引静默失效的关键子句。加上之后,Oracle 会在 MERGE 执行过程中同步扫描并修正全局索引里所有指向被合并分区的条目——本质上等于隐式触发了全量重建。需要注意以下几个要点:
- 语法必须紧跟在主语句后、分号前:
ALTER TABLE t MERGE PARTITIONS p1, p2 INTO PARTITION p_new UPDATE GLOBAL INDEXES; ONLINE与UPDATE GLOBAL INDEXES不能同时使用(MERGE PARTITIONS本身就不支持ONLINE)- 如果表上有多个全局索引,这个子句会一并维护;只要任一索引维护失败(比如空间不足、唯一键冲突),整个 DDL 就会回滚
- 已经处于
UNUSABLE状态的索引,再补这个子句也无效——DDL 会直接报错或忽略,必须先执行ALTER INDEX idx_name REBUILD
为什么加了 UPDATE GLOBAL INDEXES 还报 ORA-01502?
生产环境里经常遇到这种情况:语法没写错,执行也成功了,结果一查索引还是 UNUSABLE。排查时优先盯住这三件事:
- 执行前先查
SELECT index_name, status FROM user_indexes WHERE table_name = 'YOUR_TABLE'——如果已经有UNUSABLE的索引,DDL 不会自动修复,必须先重建 - DDL 执行中途被打断(比如 kill session 或实例崩溃),Oracle 只回滚表结构变更,索引残留中间态,状态不会自动回退
- 执行账号对索引缺少
ALTER权限:维护会跳过且不报错,只在日志里留警告,极易忽略
MERGE 分区时全局索引重建的实际开销
UPDATE GLOBAL INDEXES 的实际工作就是全索引扫描 + 重建,耗时与索引大小直接相关。实测下来,相比不加这个子句,单次 MERGE 可能慢 3 到 10 倍,尤其当索引键值分布比较稀疏、DML 并发高的时候,锁持有时间会显著拉长。
还有一个更隐蔽的风险:联机维护期间,全局索引上的 INSERT/UPDATE 会被阻塞或延迟,应用写入可能卡住——这不是理论推演,而是生产环境的高频事故。所以别光想着“能不能用”,得提前评估好窗口期和业务容忍度。
