合并分区前必须先 shrink space 以降低 HWM,否则全表扫描变慢;MERGE PARTITION 不降 HWM、不释放空间,需立即执行 SHRINK SPACE CASCADE;必须启用行移动,且 MERGE 仅支持两两相邻分区,需分步执行并带 UPDATE INDEXES;漏掉则本地索引立即失效;合并后须用 granularity=>'ALL' 重收集统计信息。
合并分区前必须先 shrink space,否则 HWM 不降
全表扫描变慢,往往不是因为数据多,而是因为高水位线(hwm)卡在高位,导致 oracle 扫描大量空块。merge partition 本身不移动 hwm,也不释放物理空间——它只是把两个分区的数据重写进一个分区段里,原分区段仍保留(哪怕已空),hwm 还钉在原来位置。
所以 MERGE 后必须立刻跟上 ALTER TABLE ... SHRINK SPACE CASCADE,否则 SELECT COUNT(*)、DBMS_STATS.GATHER_TABLE_STATS 仍会误判数据量,执行计划继续走错。
- 执行前确保表启用了行移动:
ALTER TABLE t ENABLE ROW MOVEMENT -
SHRINK SPACE需要独占表级锁(非排他,但会阻塞 DDL 和部分 DML),建议在低峰期操作 - 加
CASCADE是关键:它会连带 shrink 所有本地索引分区,避免后续索引扫描扫空叶块
MERGE PARTITION 只能两两相邻合并,不能跳步或批量
想把 p0–p3 四个分区一次合并成一个?语法不支持。Oracle 12c 的 MERGE PARTITIONS 是严格二元操作,且只接受两个相邻的 RANGE 或 LIST 分区,目标分区必须是其中之一。
常见报错直接暴露限制:
-
ORA-14054:写了三个及以上分区名,如MERGE PARTITIONS p0,p1,p2 INTO PARTITION p2 -
ORA-14055:p0和p2中间缺p1,逻辑不相邻 -
ORA-14035:对 HASH 或复合分区表执行该命令
正确做法是分步执行:
ALTER TABLE t MERGE PARTITIONS p0, p1 INTO PARTITION p1 UPDATE INDEXES; ALTER TABLE t MERGE PARTITIONS p1, p2 INTO PARTITION p2 UPDATE INDEXES; ALTER TABLE t MERGE PARTITIONS p2, p3 INTO PARTITION p3 UPDATE INDEXES;
每一步都重写数据、重建本地索引段、生成归档日志。中间失败无法回滚,只能人工清理残留状态。
UPDATE INDEXES 不是可选项,是保命操作
漏掉 UPDATE INDEXES,所有 local 索引分区会立刻变成 UNUSABLE 状态,查询一走索引就报错 ORA-01502。这不是延迟失效,是立即不可用。
global 索引不受影响(Oracle 自动维护),但务必验证:
- 查
USER_INDEXES.STATUS是否为VALID - 查
USER_IND_PARTITIONS.STATUS对 local 索引是否全为USABLE - 别信“等凌晨自动 job”,用
DBMS_PART.CLEANUP_GIDX('SCHEMA', 'TABLE_NAME')主动触发异步清理
亿级表合并后必须重收集统计信息
MERGE 完成后,USER_TAB_PARTITIONS.NUM_ROWS 仍是各源分区旧值之和,优化器看到“总行数没变”,可能继续选错执行路径(比如拒绝走分区剪枝)。
必须强制全量重收集:
DBMS_STATS.GATHER_TABLE_STATS( ownname => 'SCHEMA', tabname => 'TABLE_NAME', granularity => 'ALL', method_opt => 'FOR ALL COLUMNS SIZE AUTO', cascade => TRUE );
重点是 granularity => 'ALL':它会重新统计每个新分区的行数、块数、空块数,让 DBA_TAB_STATISTICS 真实反映合并后的物理结构。忽略这步,等于白干。
碎片整理真正的难点不在命令怎么写,而在于 HWM、索引状态、统计信息这三者必须同步更新。少做一步,性能可能不升反降。











