GLOBAL索引本身不导致物化视图失效,但EXCHANGE PARTITION会因ROWID失效、物化视图日志断裂及元数据脱节使物化视图变为UNUSABLE;GLOBAL索引掩盖该问题,因其VALID状态易误导用户忽略STALENESS检查。

GLOBAL 索引本身不会直接导致物化视图失效,但分区交换(EXCHANGE PARTITION)操作会破坏物化视图日志与基表之间的物理一致性,而 GLOBAL 索引的存在常掩盖这一问题——尤其当索引列包含被交换分区的键值时,物化视图刷新会因元数据断裂或 ROWID 失效而退化为 COMPLETE 或报错。
EXCHANGE PARTITION 为什么让物化视图变 UNUSABLE
物化视图状态变为 UNUSABLE 的根本原因是:Oracle 在执行 EXCHANGE PARTITION 时,会隐式提交并重置目标分区的段结构,导致以下三项关键信息脱节:
- 基表原分区的
ROWID全部失效(新分区数据来自另一张表,物理位置完全不同) - 物化视图日志
MLOG$_xxx中已记录的旧ROWID指向空地址,后续FAST刷新无法定位变更行 -
DBA_MVIEW_LOGS.ROWIDS字段被清空为NO,DBMS_MVIEW.EXPLAIN_MVIEW返回FAST_REFRESHABLE = 'NO'
此时即使物化视图定义没改、GLOBAL 索引仍 VALID,优化器也拒绝增量路径,STALENESS 直接置为 UNUSABLE。
GLOBAL 索引加剧了失效的隐蔽性
GLOBAL 索引不按分区键本地管理,其 B-tree 覆盖全表数据。这带来两个误导性现象:
- 查询执行计划可能仍走该索引,看起来“能用”,但实际扫描的是过期或不完整数据(因物化视图未刷新)
-
DBA_INDEXES.STATUS显示VALID,让人误以为索引健康 → 忽略检查DBA_MVIEWS.STALENESS和MLOG$_xxx行数 - 若
GLOBAL索引列含分区键(如(sales_date, customer_id)),交换后新分区数据在索引中存在,但物化视图里没有对应行 → 数据逻辑不一致
交换后必须立即做的三件事
不能只重建索引或刷新物化视图——必须先修复底层一致性:
- 先
DROP MATERIALIZED VIEW LOG ON base_table,再重建日志,且必须显式带WITH ROWID, INCLUDING NEW VALUES(EXCHANGE后ROWID已变,旧日志不可复用) - 重建后立刻执行
DBMS_STATS.GATHER_TABLE_STATS收集日志表统计信息,否则优化器对MLOG$_xxx扫描走全表 - 运行
ALTER MATERIALIZED VIEW mv_name COMPILE,再调DBMS_MVIEW.REFRESH('mv_name', 'F')——跳过COMPILE会导致刷新静默失败
如何避免下次再踩坑
核心是切断 EXCHANGE 对物化视图链路的冲击:
- 禁用自动刷新调度,在交换前手动执行
DBMS_MVIEW.REFRESH('mv_name', 'C')(完全刷新),确保物化视图与交换后数据对齐 - 若必须用
FAST刷新,交换后不要依赖原有日志;改用ATOMIC_REFRESH => FALSE+ 分区级INSERT /*+ APPEND */手动补数据 - 监控脚本里增加检查:
SELECT COUNT(*) FROM MLOG$_base_table,若交换后长期为 0,说明日志捕获已断
真正危险的不是 GLOBAL 索引,而是把索引状态等同于物化视图可用性——它们分属不同机制,VALID 索引下,物化视图可以是 UNUSABLE,而且毫无警告。











