EXCHANGE PARTITION能秒级完成迁移,因其仅交换段指针而不移动数据;前提是结构严丝合缝(列类型、长度、精度等字节级一致)、数据范围合规(所有行满足分区键条件)、索引状态可控(本地索引需匹配,全局索引需显式维护),否则直接报ORA-14097或ORA-14099中断。
EXCHANGE PARTITION 能秒级完成迁移,**前提是结构严丝合缝、数据范围合规、索引状态可控**。它不搬数据,只换段指针;一旦出错,不是慢,而是直接报错中断。
ORA-14097 报错:列定义看似一样,其实差在细节
这是最常卡住人的第一步。oracle 不接受“差不多”,只认字节级一致。
-
DATA_TYPE、DATA_LENGTH、DATA_PRECISION、DATA_SCALE、CHAR_LENGTH、NULLABLE必须逐列完全相同 -
VARCHAR2(100)和VARCHAR2(100 CHAR)视为不同类型;NUMBER和NUMBER(10,0)也不等价 - 源表含虚拟列?目标分区表也得有;源表用
TIMESTAMP,目标分区不能是DATE - 查证方式:别靠肉眼比 DDL,执行
SELECT column_name, data_type, data_length, nullable, data_precision, data_scale FROM user_tab_columns WHERE table_name IN ('SOURCE_TABLE', 'TARGET_PARTITIONED_TABLE') ORDER BY column_id;
ORA-14099 报错:数据值越界,WITHOUT VALIDATION 是双刃剑
它跳过范围校验,但不解决数据本身违规的问题——后续查询可能返回空或触发运行时错误。
- 比如目标分区定义为
LESS THAN (DATE '2025-01-01'),而源表含sale_date = DATE '2025-01-15',就必然失败 -
WITHOUT VALIDATION仅绕过该检查,但若源表有主键/唯一约束,Oracle 会强制走WITH VALIDATION(不管是否显式写) - 真正安全的做法:提前用
WHERE sale_date 过滤建表,或用 <code>CREATE TABLE AS SELECT ...带条件导出
INCLUDING INDEXES 怎么用才不翻车
它只管本地索引(LOCAL),对全局索引(GLOBAL)完全无感。加了≠万事大吉。
- 源表必须已建好同名、同列顺序、同排序方向、同
COMPRESS设置的本地索引,否则报ORA-14643 - 加了
INCLUDING INDEXES后,对应本地索引分区会绑定过去,但状态变为UNUSABLE,需手动ALTER INDEX ... REBUILD PARTITION - 全局索引不会自动更新,会变
UNUSABLE;想让它保持可用,只能加UPDATE GLOBAL INDEXES,但该操作要全表扫描,失去秒级意义 - 更稳妥策略:先不加
INCLUDING INDEXES,交换完再对新表单独建本地索引(CREATE INDEX ... LOCAL ON table_name(partition_name))
交换后查询变慢?大概率是统计信息丢了
EXCHANGE PARTITION 不继承统计信息,原分区的 NUM_ROWS 归零,优化器立刻误判为空表。
- 交换前,必须对源表收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS('SCHEMA','STAGING_TABLE') - 交换后,立即对目标分区收集:
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCHEMA', tabname => 'PARTITIONED_TABLE', partname => 'P_202504') - 别依赖自动收集——它通常滞后,且不保证覆盖刚交换进来的分区
- 如果源表已有锁住的统计信息(
LOCK_TABLE_STATS),交换后新表不会自动继承,仍需主动收集
ALTER TABLE ... EXCHANGE PARTITION,而是交换前花十分钟校验结构、确认数据范围、预建索引、收好统计信息——这些动作不体现在执行时间里,却决定整件事成不成。











