alter table move 或 shrink space 会导致索引失效,因行物理地址(rowid)全部变更,索引叶节点中旧rowid失效而变为unusable;enable row movement仅是前提条件,本身不触发失效。
row movement 本身不会导致索引失效 —— 真正让索引变 unusable 的是后续执行的 alter table ... move 或 shrink space 操作。开启 row movement 只是“允许行物理移动”的前提条件,它不改变任何索引结构,也不触发行迁移或段重建。
ALTER TABLE ... MOVE 为什么会把索引搞成 UNUSABLE
MOVE 是段级重建:Oracle 分配新段、逐行拷贝数据、原子切换段头,所有行的 ROWID 全部变更。而 B-tree 索引叶节点里存的是 <code>KEY → ROWID 映射,旧 ROWID 一失效,索引条目就指向空地址或错误块。
- 非分区索引(包括函数索引、位图索引)全部变为
UNUSABLE - 全局索引(Global Index)同样失效,除非显式加
UPDATE GLOBAL INDEXES - 本地分区索引(Local Index)不受影响,因为每个分区索引只绑定对应分区段
执行完 MOVE 后必须立刻检查:
SELECT index_name, status FROM user_indexes WHERE table_name = 'YOUR_TABLE';几乎必然看到
UNUSABLE。
SHRINK SPACE 和 MOVE 对索引的影响差异在哪
很多人误以为两者效果一样,其实关键区别在“是否换段”和“是否强制重建索引”:
-
SHRINK SPACE是原地紧缩:靠DELETE + INSERT在原段内重组,ROWID仍会变,但 Oracle 内部自动维护索引一致性(只要没加CASCADE,索引保持VALID) -
MOVE是彻底换段:不保留原段,索引无法自动适配,必须人工重建
所以:
-
SHRINK SPACE后查索引状态仍是VALID(默认不带CASCADE) -
MOVE后查索引状态一定是UNUSABLE,无例外
ENABLE ROW MOVEMENT 被误用的典型场景
ROW MOVEMENT 开启后,以下操作才可能触发行物理移动:
-
UPDATE主键或分区键列(如更新PARTITION KEY导致跨分区迁移) FLASHBACK TABLE-
SHRINK SPACE COMPACT(第一步)
但它不等于自动触发 MOVE,也不影响索引可用性 —— 除非你紧接着执行了 MOVE 或 SHRINK SPACE。
最容易被忽略的一点是:
哪怕只是 PL/SQL 里缓存了一把 ROWID 做批量更新,中间穿插了 MOVE,那批缓存的 ROWID 就全作废,UPDATE ... WHERE ROWID = :rid 会查不到行,不报错但实际零更新。别依赖“刚查出来的 ROWID 还能用”。











