不能。物化视图本身不支持EXCHANGE PARTITION,仅可交换其依赖的基表或物化视图日志表,且须确保日志覆盖、结构一致、时间戳连续,否则增量刷新会失败或漏数据。
物化视图能否直接交换分区?
不能。materialized view 本身不是表,不支持 exchange partition。你真正能交换的,是物化视图所依赖的**基表**(或其物化视图日志表),但必须确保交换后物化视图的刷新逻辑仍能正确识别变更。
常见误操作:把一张新分区表和基表做 EXCHANGE PARTITION 后立刻刷新物化视图,结果查不到新数据,甚至报 ORA-12008: error in materialized view refresh path —— 根本原因通常是物化视图日志没覆盖被交换进来的分区,或日志中缺失相应 DML 时间戳。
交换前必须满足的三个条件
要让交换后的分区被快速、正确地纳入物化视图增量刷新(FAST REFRESH),需同时满足:
- 基表已启用物化视图日志,且日志包含
ROWID和所有物化视图 SELECT 列(尤其是用于连接/聚合的列) - 被交换进来的分区表(即
EXCHANGE的WITH TABLE)必须:已建好相同结构的物化视图日志;且该日志中已有对应时间段的变更记录(不能是空日志) - 交换操作需使用
INCLUDING INDEXES和WITHOUT VALIDATION(否则会触发全量校验,抵消“快速”优势)
典型安全交换流程(以 RANGE 分区为例)
假设基表 sales_fact 按月分区,当前最大分区是 P_202405,你要把预处理好的 sales_jun_2024 表作为 P_202406 加入:
ALTER TABLE sales_fact EXCHANGE PARTITION P_202406 WITH TABLE sales_jun_2024 INCLUDING INDEXES WITHOUT VALIDATION;
紧接着立即执行:
INSERT INTO mlog$_sales_fact
SELECT mrow#, snaptime$$, dmltype$$, old_new$$, change_vector$$, ...
FROM mlog$_sales_jun_2024
WHERE snaptime$$ > TO_DATE('2024-05-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS');
注意:mlog$_sales_jun_2024 必须存在且非空;snaptime$$ 值需严格大于上一次物化视图刷新时间,否则 DBMS_MVIEW.REFRESH 会跳过它。
为什么物化视图刷新仍可能失败?
最常被忽略的是物化视图日志的 SEQUENCE$$ 和 SNAPTIME$$ 一致性。交换进来的新分区若来自另一套 ETL 环境,其日志中的 SNAPTIME$$ 可能早于主表日志的最小值,导致刷新时漏数据。
验证方法:
- 查
SELECT MIN(snaptime$$) FROM mlog$_sales_fact - 查新分区日志:
SELECT MIN(snaptime$$), MAX(snaptime$$) FROM mlog$_sales_jun_2024 - 二者交集必须非空,且新日志的
MIN(snaptime$$)≤ 主日志的MAX(snaptime$$)
跨库同步或离线加载的分区,务必在交换前用 DBMS_MVIEW.PURGE_LOG 清理旧日志,并手动补全带正确时间戳的日志行 —— 这步没有捷径。











