MOVE表后索引立即失效,因索引仍指向原rowid而数据物理位置已变,导致ORA-01502错误;需重建索引、处理LOB/IOT溢出段、注意全局索引失效及迁移顺序。

不能只执行 ALTER TABLE ... MOVE 就完事——索引会立刻失效,应用可能报 ORA-01502。
为什么 move 表后索引就不可用
Oracle 的 MOVE 操作本质是重建表段(segment),但不会触碰索引段。索引仍指向原表位置的 rowid,而 move 后数据物理位置已变,索引条目失效。哪怕只是普通主键或唯一约束依赖的索引,也会变成 UNUSABLE 状态。
常见错误现象:ORA-01502: index 'XXX' or partition of such index is in unusable state,尤其在插入、更新或带 where 条件的查询时触发。
- LOB 类型字段的表,
MOVE前必须先处理LOB段(单独MOVE LOB (...) STORE AS) - IOT 表的溢出段(
OVERFLOW)需单独MOVE,不能随主表一起操作 - 全局索引在分区表
MOVE PARTITION后默认失效,除非加UPDATE GLOBAL INDEXES
生成安全的批量迁移语句要注意什么
直接拼 SELECT 'ALTER TABLE...' FROM dba_segments 很危险——它会包含回收站对象(BIN$ 开头)、临时段、回滚段、系统对象等,这些不能 ALTER。
推荐用 dba_tables 和 dba_indexes 限定范围,且过滤掉无效/废弃对象:
- 排除回收站:
AND owner NOT IN (SELECT owner FROM dba_recyclebin) - 跳过 IOT 溢出段:
AND iot_type IS NULL(查dba_tables) - 跳过已删除索引:
AND dropped = 'NO'(查dba_indexes) - 跳过 LOB 索引:
AND index_type != 'LOB' - 确认无 LONG 字段:
SELECT data_type FROM dba_tab_columns WHERE owner = 'XXX' AND table_name = 'YYY' AND data_type = 'LONG',有则需先转为 CLOB
示例(生成表迁移语句):
SELECT 'ALTER TABLE ' || owner || '.' || table_name || ' MOVE TABLESPACE NEW_TS;'<br>FROM dba_tables<br>WHERE tablespace_name = 'OLD_TS'<br> AND owner NOT IN (SELECT owner FROM dba_recyclebin)<br> AND iot_type IS NULL;
分区表迁移要分两步写不同语法
普通表用 MOVE TABLESPACE,分区表必须指定 PARTITION 或 SUBPARTITION,且索引重建也分全局/局部。
- 移动单个分区:
ALTER TABLE tab_name MOVE PARTITION part_name TABLESPACE NEW_TS; - 移动子分区(复合分区):
ALTER TABLE tab_name MOVE SUBPARTITION subpart_name TABLESPACE NEW_TS; - 重建局部索引分区:
ALTER INDEX idx_name REBUILD PARTITION part_name TABLESPACE NEW_TS; - 重建全局索引:
ALTER INDEX global_idx REBUILD TABLESPACE NEW_TS;(不能带PARTITION) - 想避免全局索引失效?加
UPDATE GLOBAL INDEXES选项,但会延长锁表时间
注意:如果表有 LOB 字段,还需额外生成 MOVE LOB 语句,例如:
ALTER TABLE owner.tab_name MOVE LOB(lob_col) STORE AS (TABLESPACE NEW_TS);
执行顺序和后续动作不能省
迁移不是“生成→执行”两步就结束。真实环境必须按顺序做,否则容易卡住或引发连锁故障:
- 先迁移所有表(含分区表各分区),再迁移索引;顺序颠倒会导致索引 rebuild 失败
- 索引 rebuild 建议加
PARALLEL 4加速,但别盲目设高(如PARALLEL 16可能压垮 PGA) - 非在线 rebuild(即不加
ONLINE)会阻塞 DML,生产环境优先用REBUILD ONLINE,但需额外空间 - 迁移完成后,必须手动收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS,否则执行计划可能劣化 - 检查是否有物化视图日志、函数索引依赖的 PL/SQL 包权限,这些不会自动更新,需人工确认
最容易被忽略的是:move 后表的 DEFAULT TABLESPACE 属性没变,新插入分区或子分区仍可能落到旧表空间——得补一句:ALTER TABLE ... MODIFY DEFAULT ATTRIBUTES TABLESPACE NEW_TS;


















