DBMS_REDEFINITION是唯一能在线消除行迁移的方法,通过重建中间表并原子切换,使新表段从零紧凑填充,彻底清除迁移链;需调低PCTFREE、禁用COMPRESS、启用ROW MOVEMENT,并手动清理索引/LOB/物化视图日志。

DBMS_REDEFINITION 是唯一能在不锁表前提下消除行迁移的在线手段。直接 ALTER TABLE ... MOVE 会加排他锁,而重定义通过重建中间表+原子切换,让新表段从头按需分配块,天然绕过旧段中已碎裂、无法复用的迁移链。
为什么重定义能消除行迁移?
行迁移本质是 UPDATE 导致行变长、原块放不下,Oracle 把整行挪到新块并留个指针(即“迁移链”)。旧段里这些指针和空洞不会自动清理,即使后续 DELETE 也未必回收——除非重建段。FINISH_REDEF_TABLE 后旧段被 Oracle 自动 drop,新表段从零开始填充,所有行都紧凑存放,迁移链彻底消失。
- 不是靠
SHRINK SPACE:该命令只整理现有段内空闲块,对已存在的迁移链无效 - 不是靠
ENABLE ROW MOVEMENT:它只是允许后续迁移发生,不修复已有迁移 - 真正起效的是“重建+切换”这个动作本身,且必须用
CONS_USE_PK方式(避免引入M_ROW$$隐藏列干扰)
中间表建表时的关键参数
中间表不能照抄原表 DDL,否则新建段仍会继承高 PCTFREE 或碎片化存储参数,导致新表一上来就容易迁移。重点改三项:
-
PCTFREE设为5或10(原表若设了40就必须调低) - 显式指定
SEGMENT CREATION IMMEDIATE,避免延迟段创建引发后续问题 - 去掉
COMPRESS(除非你明确需要压缩;压缩表在 UPDATE 时更容易触发迁移)
示例:CREATE TABLE t_interim AS SELECT * FROM t_orig WHERE 1=0 不够——要手工写 DDL,确保存储参数干净。
执行前必须验证的三个点
跳过这三步,START_REDEF_TABLE 可能卡住,或 FINISH_REDEF_TABLE 失败后残留中间表和物化视图日志:
-
DBMS_REDEFINITION.CAN_REDEF_TABLE('SCHEMA','TABLE_NAME', DBMS_REDEFINITION.CONS_USE_PK)必须返回无错,否则检查:表是否含LOB、是否在SYS下、是否有未提交长事务 - 目标表空间剩余空间 ≥ 原表
dba_segments.bytes的 1.2 倍(增量同步期间可能临时膨胀) -
SELECT row_movement FROM dba_tables WHERE table_name = 'T_INTERIM'和原表都应为ENABLED;若为DISABLED,执行ALTER TABLE t_interim ENABLE ROW MOVEMENT
完成后的残留清理要点
FINISH_REDEF_TABLE 执行成功后,空间释放是即时的,但以下对象不会自动迁移,必须手动处理,否则它们仍占用原表空间、甚至引发 ORA-01652:
- 索引:用
COPY_TABLE_DEPENDENTS显式同步,否则旧索引留在原表空间,状态变为UNUSABLE - LOB 段:即使表迁移了,
LOB仍驻留在原表空间,需单独执行ALTER TABLE t MOVE LOB(c) STORE AS (TABLESPACE new_ts) - 物化视图日志:重定义过程自动创建,但
FINISH后不会自动删除,要用DROP MATERIALIZED VIEW LOG ON t
最容易被忽略的是:重定义后查 v$session_longops,若还有 Online Redefinition 相关操作残留,说明某步没 clean up 干净,得用 ABORT_REDEF_TABLE 回滚并重试。











