ALTER INDEX REBUILD ONLINE TABLESPACE 必须严格按 REBUILD→ONLINE→TABLESPACE 顺序书写,否则报 ORA-00922;ONLINE 期间 DML 不阻塞但受未提交事务影响,中断后需 DBMS_REPAIR.ONLINE_INDEX_CLEAN 清理残留;重建后需验证段位置与元数据,并注意空间开销及索引类型限制。
可以直接用 alter index ... rebuild online tablespace,但必须注意顺序、锁行为和残留状态——不是加个 online 就万事大吉。
ALTER INDEX REBUILD ONLINE TABLESPACE 语句写法必须严格遵循顺序
Oracle 不接受 TABLESPACE 放在 ONLINE 后面的写法,比如 ALTER INDEX idx1 REBUILD TABLESPACE users ONLINE 会报错 ORA-00922: missing or invalid option。
正确顺序是:REBUILD → ONLINE → TABLESPACE → 其他子句(如 PARTITION、POLICY 等)。
-
ALTER INDEX idx1 REBUILD ONLINE TABLESPACE users;✅ -
ALTER INDEX idx1 REBUILD TABLESPACE users ONLINE;❌ - 如果要并行,写成:
ALTER INDEX idx1 REBUILD ONLINE TABLESPACE users PARALLEL 8; - 重建完记得关并行度(否则后续 DML 可能意外走并行):
ALTER INDEX idx1 NOPARALLEL;
ONLINE 重建期间 DML 不阻塞,但有真实等待场景
加 ONLINE 后,索引基表仍支持 INSERT/UPDATE/DELETE,但以下情况会卡住重建:
- 存在未提交的事务(尤其是对同一张表的长事务),
REBUILD ONLINE会在开始和结束阶段申请 TM 锁(mode=4),会被该事务持有的 TX 锁阻塞; - 多个并发
REBUILD ONLINE操作不会互相阻塞,但都依赖同一张表的 TM 锁协调; - 如果执行中被 Ctrl+C 或 kill session 中断,可能残留
SYS_JOURNAL_*临时段和内部标志位,后续再对该索引做REBUILD、DROP或ANALYZE会报ORA-08104: index is being online built or rebuilt; - 此时需手动清理:
DBMS_REPAIR.ONLINE_INDEX_CLEAN(传入object_id),或等后台进程自动回收(通常几分钟内)。
重建后表空间归属和段属性变化要验证
REBUILD ONLINE TABLESPACE 成功后,索引段会迁移到目标表空间,但部分元数据可能滞后:
- 查
dba_segments确认物理位置:SELECT segment_name, tablespace_name FROM dba_segments WHERE segment_name = 'IDX1' AND owner = 'SCOTT'; - 查
dba_indexes看逻辑定义:SELECT tablespace_name, status, degree FROM dba_indexes WHERE index_name = 'IDX1' AND owner = 'SCOTT';—— 注意degree会继承PARALLEL子句值,不显式设NOPARALLEL就一直保留; - 如果原索引是函数索引或位图索引,
ONLINE不支持,会直接报错ORA-01438: value larger than specified precision allowed for this column(实际是类型不兼容),得改用普通REBUILD; - LOB 索引不能用
ONLINE重建,必须先移动 LOB 段,再重建主索引。
批量迁移前务必预判空间与时间开销
在线重建不是“零成本”:它会同时持有旧索引段 + 新索引段 + SYS_JOURNAL_* 日志段,高峰期容易触发表空间不足(ORA-01652)。
- 估算新索引大小:
SELECT bytes/1024/1024 MB FROM dba_segments WHERE segment_name = 'IDX1' AND owner = 'SCOTT'; - 目标表空间空闲空间至少为原大小 × 2.5(含日志段+排序临时段);
- 避免在业务高峰执行;建议用
ROWNUM 先生成几条语句测试语法和权限:<code>SELECT 'ALTER INDEX '||index_name||' REBUILD ONLINE TABLESPACE users;' FROM dba_indexes WHERE owner = 'SCOTT' AND tablespace_name != 'USERS' AND status = 'VALID' AND ROWNUM - 执行完别忘了检查:
SELECT index_name, status FROM dba_indexes WHERE owner = 'SCOTT' AND status != 'VALID';—— 出现UNUSABLE说明某步失败了,不能忽略。
真正麻烦的从来不是语法,而是中断后的残留状态、未提交事务的隐式阻塞、以及并行度遗留带来的后续性能抖动。动手前先看锁、算空间、留退路。


















