Oracle MERGE PARTITIONS 必须显式指定两个相邻分区名,不支持通配符或FOR VALUES;操作会物理移动数据并锁表,需验证边界值、补全LIST值列表,且DEFAULT分区不可参与合并。
ALTER TABLE … MERGE PARTITIONS 语法必须带分区名,不能用通配符
oracle 不支持 merge partitions 时用 for values 或通配符自动选分区,必须显式写出两个相邻分区的名称。常见错误是以为能像 drop partition 那样只写范围条件,结果报 ora-14048:「a partition maintenance operation may not be combined with other operations」——其实根本不是组合问题,而是语法不合法。
实操建议:
- 先查清楚目标分区是否真正「相邻」:对
RANGE分区,后一分区的VALUES LESS THAN必须等于前一分区的上界;对LIST分区,两分区的VALUES IN列表不能有交集,且合并后需覆盖全部原值 - 用
SELECT partition_name, high_value FROM user_tab_partitions WHERE table_name = 'YOUR_TABLE'确认分区顺序和边界值,尤其注意HIGH_VALUE是表达式,需用DBMS_METADATA或TO_LOB解析才能看清真实值 -
LIST分区合并后,新分区的VALUES IN必须显式列出所有原值,Oracle 不会自动去重或排序
MERGE PARTITIONS 会重建整个分区数据,不是元数据操作
很多人误以为 MERGE PARTITIONS 类似于 RENAME,只是改个名字,实际它会物理移动数据:把旧分区的所有行读出、按新分区键重新计算位置、写入新分区段。这意味着执行期间不仅锁表(EXCLUSIVE DML 锁),还会触发大量 I/O 和 redo 日志,大表可能卡住数小时。
实操建议:
- 提前评估数据量:
SELECT num_rows, blocks FROM user_tab_partitions WHERE table_name = 'T' AND partition_name IN ('P1','P2'),若总行数超千万,务必在低峰期操作 - 确保目标表空间有足够空闲空间:新分区大小 ≈ 原两分区之和,且排序区(
PGA)需容纳中间结果,sort_area_size或pga_aggregate_target过小会导致磁盘排序,进一步拖慢速度 - 不要在
NOLOGGING表上盲目加NOLOGGING选项——MERGE PARTITIONS本身不支持NOLOGGING子句,强行加会报ORA-14049
LIST 分区合并后,VALUES IN 必须手动补全,漏值直接导致 INSERT 失败
LIST 分区不像 RANGE 有天然连续性,合并时 Oracle 不验证值集合是否完备。如果原分区 P1 VALUES IN ('A','B') 和 P2 VALUES IN ('C') 合并为 P12,但语句写成 MERGE PARTITIONS P1, P2 INTO PARTITION P12 VALUES IN ('A','C'),那插入 'B' 就会报 ORA-14400:「inserted partition key does not map to any partition」。
实操建议:
- 合并前用
SELECT DISTINCT col FROM t PARTITION (p1) UNION SELECT DISTINCT col FROM t PARTITION (p2)拉出完整值列表,再拼进VALUES IN - 合并后立刻测试:
INSERT INTO t VALUES ('B'),别等应用报错才回头查 - 如果原分区含
DEFAULT,不能参与MERGE——ORA-14074会直接拒绝,得先用SPLIT PARTITION把默认值挪出去
合并 RANGE 分区时,HIGH_VALUE 边界必须严格匹配,隐式转换很危险
RANGE 分区合并要求前一分区的 HIGH_VALUE 字面值,必须与后一分区的 HIGH_VALUE 完全一致。比如 P1 VALUES LESS THAN (TO_DATE('2023-01-01','YYYY-MM-DD')) 和 P2 VALUES LESS THAN (DATE '2023-01-01') 看似相等,但内部存储格式不同,MERGE 会失败并报 ORA-14054。
实操建议:
- 统一用 ANSI 日期字面量
DATE '2023-01-01'或时间戳字面量TIMESTAMP '2023-01-01 00:00:00',避免TO_DATE带格式掩码 - 对
NUMBER类型边界,确认是否用了科学计数法或尾部零(如1000vs1E3),它们在HIGH_VALUE中不等价 - 用
DBMS_METADATA.GET_DDL('TABLE', 'T')导出 DDL,逐字比对两个分区的VALUES LESS THAN子句,别信USER_TAB_PARTITIONS.HIGH_VALUE的显示结果
HIGH_VALUE 时没解析表达式,或者 LIST 合并漏了某个值——这两处没日志、不报语法错,但后续所有写入都失败。










