没有真正“在线迁移数据段”的原子操作,必须分步处理:alter table ... move tablespace 会加排他锁阻塞dml;dbms_redefinition是唯一真在线方案,但需主键或rowid映射;索引、lob、分区须单独迁移;迁移后需清理残留段、收缩文件并验证一致性。

没有真正“在线迁移数据段”的原子操作,必须按对象类型分步处理,且每类操作的锁行为、依赖关系和后置动作都不同。
ALTER TABLE ... MOVE TABLESPACE 会锁表吗
会,而且是排他锁(exclusive DML lock),整个迁移过程阻塞所有 INSERT/UPDATE/DELETE,只允许 SELECT(取决于隔离级别)。MOVE 操作本质是重建表段,Oracle 需要先读取原表所有行,写入新位置,再切换段指针,最后释放旧段——中间不能有并发修改。即使加 ONLINE 关键词(12c+ 支持),也仅适用于索引组织表或带 ENABLE ROW MOVEMENT 的堆表,对普通堆表无效。
- 如果业务无法接受秒级以上锁表,
MOVE不是选项 -
MOVE后索引全部失效(STATUS = UNUSABLE),必须显式REBUILD - LOB 字段不会随表一起迁移,需单独执行
MOVE LOB语句
DBMS_REDEFINITION 是唯一真在线方案
它通过创建中间影子表、同步增量变更、原子切换的方式实现业务无感知迁移,但前提是表必须有主键或能基于 ROWID 建立一致性映射。没有主键的表也能做,但会引入隐藏列 M_ROW$$,且不支持索引组织表。
- 检查可行性:
DBMS_REDEFINITION.CAN_REDEF_TABLE('SCHEMA','TABLE_NAME', DBMS_REDEFINITION.CONS_USE_PK) - 启动重定义:
DBMS_REDEFINITION.START_REDEF_TABLE指定目标表空间 - 同步期间变更:
DBMS_REDEFINITION.SYNC_INTERIM_TABLE可多次调用减少切换时间 - 切换完成:
DBMS_REDEFINITION.FINISH_REDEF_TABLE—— 此刻才真正交换段指针,耗时极短
注意:过程中临时表占用额外空间,且 FINISH 阶段仍需短暂获取 DDL 锁(通常毫秒级)。
索引、LOB、分区必须单独处理
即使表本身用 DBMS_REDEFINITION 迁移了,它的索引、LOB 段、分区元数据仍留在原表空间,因为它们是独立段对象。遗漏会导致迁移后空间未释放,甚至引发 ORA-01652(无法扩展临时段)等错误。
- 索引重建:
ALTER INDEX idx_name REBUILD TABLESPACE new_ts—— 会锁索引,但不影响基表 DML - LOB 迁移:
ALTER TABLE t MOVE LOB(c) STORE AS (TABLESPACE new_ts)—— 锁整张表,不可并发 - 分区迁移:
ALTER TABLE t MOVE PARTITION p1 TABLESPACE new_ts—— 只锁该分区,其他分区仍可读写
批量生成语句时,务必过滤掉系统生成的隐式索引(如以 $ 结尾的索引名),否则 REBUILD 会失败。
别忽略迁移后的清理与验证
迁移不是执行完 SQL 就结束。常见疏漏点:旧表空间的数据文件没 shrink,USER_SEGMENTS 里残留临时段,或者忘记检查索引状态是否全为 VALID。
- 查残留:
SELECT segment_name, segment_type FROM user_segments WHERE tablespace_name = 'OLD_TS' - 收缩文件:
ALTER DATABASE DATAFILE '/path/old01.dbf' RESIZE 1G—— 必须先确保里面没活动段 - 验证一致性:
ANALYZE TABLE t VALIDATE STRUCTURE CASCADE(慎用,大表会锁)或对比COUNT(*)和约束状态
最易被跳过的一步:确认应用连接串里没硬编码表空间名,或触发器/存储过程里引用了旧表空间路径——这类逻辑错误往往在上线后数小时才暴露。











