在线重定义通过重建表结构降低高水位、消除碎片来节省空间,而非直接压缩数据;需满足4个硬性条件,使用CONS_USE_PK方式并确保中间表干净、依赖对象同步,FINISH_REDEF_TABLE后旧段自动释放。
为什么在线重定义能节省空间?
它不是直接“压缩”数据,而是通过重建表结构来降低高水位(hwm),消除因频繁 delete 导致的段内碎片。原表可能有大量空闲块未被回收,而重定义后的新表只保留实际数据占用的空间,物理上更紧凑。
执行前必须验证的 4 个硬性条件
跳过检查直接开干,大概率卡在 START_REDEF_TABLE 或中途报错 abort。务必逐条确认:
-
DBMS_REDEFINITION.CAN_REDEF_TABLE('schema_name','table_name')必须成功执行,否则说明表不满足基础要求(比如是 IOT、含 BFILE、在 SYS/SYSTEM 下) - 目标中间表(interim table)必须与原表在同一个 schema,且不能已存在
- 用户需具备
CREATE ANY TABLE、ALTER ANY TABLE、DROP ANY TABLE、LOCK ANY TABLE、SELECT ANY TABLE权限 - 临时表空间和目标表空间必须有足够空间容纳两份数据(原表 + 中间表),尤其大表要提前测算
用主键方式重定义并收缩空间的关键步骤
推荐使用 CONS_USE_PK(主键或伪主键),比 rowid 方式更稳定、同步更快、不引入隐含列:
- 先建中间表,**不要加任何额外约束或索引**,只定义列和主键,存储参数可优化(如
SEGMENT CREATION IMMEDIATE、PCTFREE 10) - 调用
START_REDEF_TABLE时显式指定options_flag => DBMS_REDEFINITION.CONS_USE_PK - 如果原表有大量未提交的长事务,
SYNC_INTERIM_TABLE可能卡住,建议在业务低峰期操作 -
FINISH_REDEF_TABLE后,原表名自动指向新表,旧段立即释放——这才是空间真正回收的时刻
容易被忽略的“空间没省下来”的原因
重定义完成但 dba_segments.bytes 没变小?常见陷阱:
- 没执行
ALTER TABLE ... SHRINK SPACE COMPACT或ALTER TABLE ... MOVE清理原表残留(其实不用——FINISH_REDEF_TABLE已完成切换,旧段由 Oracle 自动 drop) - 中间表建表时用了和原表一样的
INITIAL和NEXT参数,导致新段仍分配过大空间 - 忘记清理依赖对象:索引、物化视图日志等不会自动迁移,要用
COPY_TABLE_DEPENDENTS显式同步,否则可能残留旧索引占空间 - 表上有未失效的触发器或外键约束,导致重定义后某些块无法立即重用
真正起效的是重建本身,不是后续 shrink;但如果你看到空间没降,八成是中间表建得不够“干净”,或者权限/空间预估出了偏差。











