Oracle按不同列重分区表的低停机实施方案可行性咨询
先回答你的第一个问题:导出参数选DATA_ONLY即可
你已经手动提前创建了新分区表的结构、主键约束,不需要导入原表的元数据,直接在expdp参数中显式添加CONTENT=DATA_ONLY就行。如果选全量导出,会把原表的非分区属性、旧索引/约束定义一并带入,导入时会和你提前建好的对象冲突触发报错。
你的方案整体思路可行,是Oracle在线重分区缩短停机窗口的标准思路,但存在几个会导致故障/数据错误的硬伤,必须调整:
导出环节缺少一致性快照配置,会导致存量数据不一致
你当前导出query用了VERSION_TSP <= sysdate,但没有加flashback参数,expdp默认不会用全局一致性快照导出,导出过程中原表持续写入会导致不同数据块的SCN不统一,后续补增量时要么漏数要么重复。
修正方式:在expdp参数中添加FLASHBACK_TIME=SYSTIMESTAMP,导出启动时会自动锚定一个固定SCN,保证导出的全量存量数据是同一个时间点的一致视图,记得同时记录下这个SCN(可以在导出日志里找到),后续补增量要用。
另外你开了parallel=8,dumpfile要改成通配符格式dumpfile=parent_table_%u.dmp,否则并行度无法生效,只能单进程写单个dmp文件,导出速度会很慢。新建分区表的主键配置不符合Oracle分区规则,建表会直接报错
你用了间隔分区(INTERVAL PARTITION),这类分区表要求所有主键、唯一约束必须包含分区键,你当前主键只有(foo, boo),没带分区键VERSION_TSP,执行建表语句会直接抛ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index错误。
修正方式:如果业务上(foo, boo, VERSION_TSP)组合确实唯一,就把VERSION_TSP加入主键;如果不满足唯一要求,就放弃间隔分区,手动预创建需要的时间范围分区。新表缺失大量依赖对象,切表后业务会直接报错
你当前只在新表建了主键和VERSION_TSP字段的索引,原表上的其他二级索引、非主键约束(CHECK/唯一约束/外键)、触发器、对象授权、字段/表注释、依赖的存储过程/视图关联都没同步,切表后这些对象要么丢失要么失效。
建议:二级索引可以等存量数据导入完成后,用并行方式创建,比边导入数据边维护索引快3~5倍,其余约束、权限、注释可以在在线阶段提前配置完成,不要堆到停机窗口操作。初始分区的设置是必要的
你提到的初始分区PARENT_TABLE_PARTITION_必须保留,间隔分区要求必须指定一个初始分区边界,只要你设置的VALUES LESS THAN (TO_DATE('2007-07-01', 'YYYY-MM-DD'))早于表中最早的VERSION_TSP值就没问题,早于这个边界的数据会全部落到这个初始分区,不会自动建更早的间隔分区。你设置的ENABLE ROW MOVEMENT也是正确的,间隔分区更新分区键时需要这个配置。增量同步逻辑有漏数风险
你当前取新表最大VERSION_TSP然后插大于这个值的数据,会漏掉两类数据:一是导出锚定SCN之前就存在、但导出时事务未提交、导出完成后才提交的旧数据;二是VERSION_TSP小于等于最大值、但在导出完成后才插入/更新到原表的数据。
修正方式:停机后先确认应用完全停掉、没有新事务写入原表,再以之前记录的导出SCN为基准,补所有原表中SCN大于导出SCN的数据,不要只用VERSION_TSP做过滤条件。如果不想依赖SCN,也可以在停机后先给原表加排他锁,确认无写入后再补全差异,逻辑更简单不容易错。切表步骤风险极高,且会破坏子表外键
你直接drop table parent_table cascade constraints是不可逆操作:一是会直接删掉所有子表关联父表的外键约束,你后续要给子表加分区的话关联关系直接断了;二是如果切表后发现问题,无法快速回滚。
修正方式:不要drop原表,用rename做切换:
rename parent_table to parent_table_old; rename parent_table_repartitioned to parent_table;
这种方式是秒级完成,如果出问题只要再rename回去就能立刻回滚,原表的所有依赖对象会保留,后续可以手动重建外键、编译失效的视图/存储过程,不会直接丢失对象。
几个优化建议,可以进一步缩短停机时间、降低风险:
- 存量数据导入完成后,在线阶段就提前收集新表的全量统计信息,补完增量后只需要收集新增分区的统计信息即可,避免切表后SQL执行计划异常。
- 新表建表时设置的
PARALLEL 8是为了加快导入速度,导完数据后记得把表和索引的并行度改回1,避免后续业务查询默认开启并行占用过多数据库资源。 - 切表完成后手动批量编译失效的依赖对象(视图、存储过程、函数等),不要等业务访问时自动编译,避免首次访问卡顿。
- 子表分区优先考虑用参考分区(REFERENCE PARTITIONING),和父表的分区规则自动对齐,后续维护成本更低。
内容的提问来源于stack exchange,提问作者anat0lius

