Oracle不支持ALTER INDEX ... MOVE TABLESPACE,必须用REBUILD切换索引表空间;需查DBA_INDEXES生成动态SQL,分区索引须单独处理各分区,重建后需手动收集统计信息。
为什么不能直接用 ALTER INDEX ... MOVE TABLESPACE?
oracle 的 alter index ... move tablespace 语法根本不存在——这是最常踩的坑。索引不能像表那样用 move,只能用 rebuild 切换存储位置。误写成 move 会报错:ora-02158: invalid create index option 或直接语法错误。
真正生效的是 ALTER INDEX ... REBUILD TABLESPACE <ts_name></ts_name>,它会重建索引结构并把新段分配到目标表空间,原索引段在完成后自动清理。
- 必须确保目标表空间存在且在线、有足够空闲空间
- 重建期间索引仍可读(但 DML 可能短暂阻塞,尤其对唯一索引或含函数索引)
- 如果索引是分区索引,需对每个分区单独
REBUILD PARTITION,不能整索引一把梭
怎么生成批量重建索引的动态 SQL?
核心是查 DBA_INDEXES(或 ALL_INDEXES),过滤出当前不在目标表空间、且属于指定用户/模式的索引,拼出 ALTER INDEX ... REBUILD TABLESPACE 语句。
下面这条 SQL 生成所有非 USERS 表空间下的普通索引(排除 LOB 索引、域索引等)的重建语句:
SELECT 'ALTER INDEX ' || owner || '.' || index_name ||
' REBUILD TABLESPACE idx_ts;' AS ddl
FROM dba_indexes
WHERE tablespace_name != 'IDX_TS'
AND owner NOT IN ('SYS', 'SYSTEM')
AND index_type = 'NORMAL'
AND status = 'VALID';
注意替换 IDX_TS 为目标表空间名;status = 'VALID' 排除失效索引(重建失效索引会失败);index_type 还可能是 FUNCTION-BASED NORMAL、BITMAP 等,按需调整。
- 执行前建议先加
AND ROWNUM 预览前几条,避免拼错 - 如果要排除主键/唯一约束关联的索引,加条件
generated = 'N'(generated = 'Y'是约束自动生成的) - 想跳过大索引(比如 >1GB)避免长事务,可连查
dba_segments加 size 过滤
执行时要不要加 ONLINE 和 PARALLEL?
加 ONLINE 能让索引重建期间支持 DML(插入/更新/删除),但代价是临时占用额外空间(维护 IOT 日志段),且不支持某些索引类型(如位图索引、域索引)。
PARALLEL 可加速重建,但需注意:并行度不是越高越好;实例级并行参数(parallel_threads_per_cpu)、表空间是否为本地管理、以及是否启用了并行 DML(ALTER SESSION ENABLE PARALLEL DML)都会影响实际效果。
- 安全起见,首次批量执行建议不加
PARALLEL,单条测试成功后再批量加PARALLEL 4 -
ONLINE对业务连续性关键,但务必确认数据库版本 ≥ 11gR2(旧版 ONLINE 限制多) - 重建后索引状态是
VALID,但统计信息不会自动更新,需后续跑DBMS_STATS.GATHER_INDEX_STATS
分区索引和不可见索引要单独处理吗?
要。分区索引不会被上面的 DBA_INDEXES 查询覆盖全貌——主查询只返回索引整体信息,分区级表空间可能各不相同。必须查 DBA_IND_PARTITIONS 单独生成每分区的 REBUILD PARTITION 语句:
SELECT 'ALTER INDEX ' || index_owner || '.' || index_name ||
' REBUILD PARTITION ' || partition_name ||
' TABLESPACE idx_ts;' AS ddl
FROM dba_ind_partitions
WHERE tablespace_name != 'IDX_TS'
AND index_owner NOT IN ('SYS', 'SYSTEM');
不可见索引(visibility = 'INVISIBLE')也能重建,不影响其可见性状态,无需额外操作;但重建后仍是不可见的,这点常被忽略。
- 全局索引(GLOBAL)不分区,走主索引查询即可;局部索引(LOCAL)必须逐分区处理
- 如果目标表空间是 ASSM(自动段空间管理),重建后索引的
PCTFREE会继承表空间默认值,原值可能被覆盖 - 脚本生成后,别直接
@xxx.sql全量执行——先挑 2–3 个典型索引手动跑通,再上自动化











