DBMS_REDEFINITION 是 Oracle 12c+ 唯一可靠支持在线将普通表转为分区表的方式,ALTER TABLE MODIFY PARTITION BY 因严苛限制在生产环境大概率失败,需严格校验结构、权限与依赖。

DBMS_REDEFINITION 是 Oracle 12c 及后续版本中唯一真正支持“在线”转换普通表为分区表的可靠方式,尤其当表含虚拟列、LOB、触发器、全局索引或物化视图日志时。ALTER TABLE ... MODIFY PARTITION BY 表面简洁,但多数生产场景下会直接报错或静默失败,不能当作通用方案。
为什么 ALTER TABLE MODIFY PARTITION BY 在生产环境大概率失败
这个语法在 12.2+ 引入,但限制极严,不是“能跑就可用”:
-
MODIFY PARTITION BY RANGE不支持LIST、HASH或INTERVAL分区类型 - 分区键列不能是
GENERATED ALWAYS AS虚拟列(比如你的TOTAL_AMOUNT) - 若原表某列为
NOT NULL但无DEFAULT,而新分区键列允许空值,立即触发ORA-14097 -
UPDATE INDEXES子句要求显式列出所有依赖唯一约束的全局索引;漏一个就ORA-14098 - 表上有物化视图日志、
REF列、审计策略或DBMS_FLASHBACK_ARCHIVE?该语句直接拒绝执行
DBMS_REDEFINITION.CAN_REDEF_TABLE 成功 ≠ 真能重定义
执行 EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SZR', 'CUSTOMER_ORDERS') 返回成功,只说明基础结构合规。你还得手动确认:
- 表必须有主键(
ORDER_ID是 OK 的),且主键列定义里不能含DEFAULT CUSTOMER_ORDERS_SEQ.NEXTVAL或SYSTIMESTAMP—— 触发器逻辑可以,但 DDL 默认值写法不行 - 检查是否存在
ROWID引用、高级队列表依赖、或启用DBMS_FLASHBACK_ARCHIVE—— 这些会让COPY_TABLE_DEPENDENTS失败 - 预留空间:临时中间表 + 原表数据 ≈ 2×原表大小;
TEMP表空间也要够(同步阶段大量排序用)
中间表建表最容易踩的三个坑
中间表不是复制粘贴原 DDL 就完事。稍不注意,START_REDEF_TABLE 就抛 ORA-14197 或导致数据不一致:
- 字段定义必须完全一致:包括长度单位 ——
VARCHAR2(120)和VARCHAR2(120 CHAR)被 Oracle 视为不同类型 - 分区键列(如
ORDER_DATE)不能加NOT NULL约束,除非原表对应列也强制非空;否则START_REDEF_TABLE直接报错 -
不要自己建索引、约束、触发器 —— 全部交给
COPY_TABLE_DEPENDENTS同步;你手动建了,后续会冲突或丢失
示例中间表语句(注意 PARTITION BY RANGE 和边界写法):
CREATE TABLE SZR.CUSTOMER_ORDERS_PART (
ORDER_ID NUMBER PRIMARY KEY,
ORDER_DATE DATE NOT NULL,
CUSTOMER_ID NUMBER NOT NULL,
CUSTOMER_NAME VARCHAR2(120),
PRODUCT_CODE VARCHAR2(50),
QUANTITY NUMBER(8),
UNIT_PRICE NUMBER(12,2),
TOTAL_AMOUNT NUMBER(14,2) GENERATED ALWAYS AS (QUANTITY * UNIT_PRICE) VIRTUAL,
ORDER_STATUS VARCHAR2(20) DEFAULT 'PENDING',
CREATED_BY VARCHAR2(60)
) PARTITION BY RANGE (ORDER_DATE) (
PARTITION P202401 VALUES LESS THAN (TO_DATE('2024-01-01', 'YYYY-MM-DD')),
PARTITION P202404 VALUES LESS THAN (TO_DATE('2024-04-01', 'YYYY-MM-DD')),
PARTITION P202407 VALUES LESS THAN (TO_DATE('2024-07-01', 'YYYY-MM-DD')),
PARTITION P_MAX VALUES LESS THAN (MAXVALUE)
);最后一步:别忘了统计信息和权限校验
重定义完成后,Oracle 不会自动收集新分区表的统计信息,查询计划可能严重劣化:
- 必须手动执行
DBMS_STATS.GATHER_TABLE_STATS,且指定GRANULARITY => 'ALL'才能覆盖所有分区 -
COPY_TABLE_DEPENDENTS默认不复制对象权限(GRANT),需单独用DBMS_REDEFINITION.COPY_TABLE_PRIVILEGES补上 - 如果原表有同义词或视图引用,重定义后需验证是否仍可访问 —— 表名没变,但底层对象已切换,部分依赖可能缓存失效
最易被忽略的是:重定义过程虽“在线”,但最终 FINISH_REDEF_TABLE 是原子交换,会短暂持有 DDL 锁;若此时恰有长事务正在更新该表,交换会被阻塞 —— 建议避开业务高峰执行。


















