dbms_redefinition 是唯一支持低停机在线重定义的方案,要求表有主键或唯一约束且无long/lob(需转securefile)、非iot/临时/集群表;执行前需通过can_redef_table检查,创建结构一致的中间分区表,启动后须sync_interim_table再finish,切换仅秒级锁表。

DBMS_REDEFINITION 是唯一能真正实现“低停机”改造的方案。其他方法(如 expdp/impdp、CTAS、ALTER TABLE ... MODIFY PARTITION)要么需锁表、要么要求 12.2+ 且对分区策略有限制,而 DBMS_REDEFINITION 在业务持续读写时完成结构切换,实际停机仅发生在最后几秒的原子切换阶段。
确认原表是否支持在线重定义
不是所有表都能直接重定义,必须满足基本前提:
- 表必须有主键或唯一约束(且所有列 NOT NULL),否则
DBMS_REDEFINITION.CAN_REDEF_TABLE会报错ORA-12089 - 不能含
LONG、LOB(含CLOB/BLOB)字段 —— 若存在,需先转为SECUREFILE并确认支持快速刷新 - 不能是索引组织表(IOT)、临时表、集群表
- 执行用户需有
EXECUTE权限在DBMS_REDEFINITION包上,且对源表和中间表所在表空间有CREATE TABLE权限
执行检查语句:
BEGIN
DBMS_REDEFINITION.CAN_REDEF_TABLE(
'CWSF3',
'CW_MZSFMX',
DBMS_REDEFINITION.CONS_USE_PK
);
END;
无报错即通过;若提示 ORA-12091(无法重定义),需先清理触发器、物化视图日志等依赖对象。
创建中间分区表要匹配原表结构
中间表不是随便建个分区表就行,它必须:
- 字段名、类型、长度、NULL 属性与原表完全一致(包括默认值、虚拟列)
- 分区键必须是原表中已存在的列,且该列在查询中高频过滤(如
SFSJ) - 建议用
INTERVAL分区替代手工写一堆VALUES LESS THAN,避免未来新增分区时再手动SPLIT - 显式指定
TABLESPACE和存储参数(PCTFREE、INITRANS),否则继承DEFAULT表空间可能引发后续空间不足
示例(适配 Oracle 19c+):
CREATE TABLE CWSF3.CW_MZSFMX_INTERIM (
JLID NUMBER(10),
SFSJ DATE,
...
) PARTITION BY RANGE (SFSJ) INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
( PARTITION p_init VALUES LESS THAN (TO_DATE('2011-01-01','yyyy-mm-dd')) )
TABLESPACE TS_PART_01
PCTFREE 10 INITRANS 3;
注意:p_init 是必须的初始分区,INTERVAL 才能生效;别漏掉 ... 处补全全部字段。
启动重定义后必须同步增量数据
调用 START_REDEF_TABLE 后,系统会自动建物化视图日志并捕获 DML 变更。但很多人忽略关键一步:在 FINISH_REDEF_TABLE 前,必须执行 SYS_SYNC_INTERIM_TABLE 或等待自动同步完成,否则最后切换时会丢数据。
- 大表首次同步耗时长,可分批调用
COPY_TABLE_DEPENDENTS(索引、约束、授权等)并设copy_indexes => 0,等主表同步完再单独建本地索引 - 若业务写入频繁,观察
V$SESSION_LONGOPS中REDEFINITION进度,避免在高峰时段执行FINISH_REDEF_TABLE -
FINISH_REDEF_TABLE是唯一加锁操作,只锁表几秒 —— 它本质是原子 rename + 索引重建 + 统计信息继承,此时应用会短暂阻塞
典型流程片段:
BEGIN
DBMS_REDEFINITION.START_REDEF_TABLE(
'CWSF3', 'CW_MZSFMX', 'CW_MZSFMX_INTERIM'
);
END;
<p>-- 等待主数据同步完成(可查 DBA_REDEFINITION_STATUS)
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('CWSF3', 'CW_MZSFMX', 'CW_MZSFMX_INTERIM');</p><p>-- 切换(停机窗口在此刻发生)
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('CWSF3', 'CW_MZSFMX', 'CW_MZSFMX_INTERIM');</p>
切换后立即验证分区有效性
别急着删中间表。先确认三件事:
- 查
DBA_TAB_PARTITIONS确认分区数量和边界是否符合预期,特别是INTERVAL分区是否已按需生成新分区 - 执行
SELECT COUNT(*) FROM CWSF3.CW_MZSFMX PARTITION (p_init)对比原表总行数,防止SYNC遗漏 - 跑几个典型业务 SQL,看执行计划是否走
PARTITION RANGE SINGLE或ITERATOR,而不是全表扫描 - 检查索引是否自动转为本地(
LOCAL)或全局(GLOBAL)—— 若原索引含分区键,COPY_TABLE_DEPENDENTS默认建LOCAL;否则需手动重建
中间表 CW_MZSFMX_INTERIM 必须保留至少 24 小时,期间若发现数据不一致或性能异常,可用 DROP TABLE ... CASCADE CONSTRAINTS 回滚(前提是没删原表依赖)。
真正容易被忽略的是:分区键的选择一旦定下就极难变更,而 DBMS_REDEFINITION 过程中若发现分区键字段存在大量 NULL 值,会导致部分数据无法落入任何分区(NULL 不满足任何 LESS THAN 条件),最终出现在 MAXVALUE 分区或报错。上线前务必用 WHERE SFSJ IS NULL 扫描原表。











