基表drop partition后物化视图staleness变为unusable而非invalid,因分区ddl破坏刷新路径;必须先alter materialized view ... compile,再检查并重建物化视图日志,否则fast刷新必然失败。

基表DROP PARTITION后物化视图STALENESS变UNUSABLE,不是INVALID
先确认问题本质:Oracle中基表执行DROP PARTITION后,物化视图的STALENESS字段通常变为UNUSABLE,而非STATUS = 'INVALID'。这两者不同——STATUS = 'INVALID'表示编译失败(如依赖列被删、函数不可用),而STALENESS = 'UNUSABLE'表示刷新能力断裂,元数据无法安全推导增量变更路径。
查状态用这条语句:
SELECT MVIEW_NAME, STALENESS, STATUS, STALENESS_REASON FROM DBA_MVIEWS WHERE MVIEW_NAME = 'YOUR_MV_NAME';
- 若
STALENESS = 'UNUSABLE'且STATUS = 'VALID':说明物化视图定义本身完好,只是因分区DDL导致刷新链路失效,重点在日志与编译 - 若
STATUS = 'INVALID':必须先验证基表结构是否还满足MV定义(比如被删的列是否仍在SELECT列表里)
必须先COMPILE再REFRESH,跳过这步必失败
ALTER MATERIALIZED VIEW ... COMPILE不是可选操作,是强制前置步骤。因为DROP PARTITION隐式提交并破坏物化视图的内部编译上下文,此时直接调用DBMS_MVIEW.REFRESH会静默忽略method => 'F'参数,甚至报ORA-12008却不透出真实错误。
- 执行
ALTER MATERIALIZED VIEW your_mv_name COMPILE后,STALENESS可能变为STALE或仍为UNUSABLE,但至少恢复了编译态 - 只有编译成功后,
REFRESH FAST才可能生效;否则一律回落COMPLETE,且可能卡在日志扫描阶段 - 如果COMPILE报错(如PLS-00302: component 'XXX' must be declared),说明基表结构已不兼容原MV定义,需重定义MV或回退DDL
物化视图日志未捕获分区操作,FAST刷新必然失败
DROP PARTITION本身不写入物化视图日志(MLOG$_xxx),即使日志建时带了INCLUDING NEW VALUES。这是Oracle设计限制:分区级DDL绕过DML日志机制,导致FAST刷新找不到差异行,最终拒绝执行。
- 查日志是否“真有效”:
SELECT ROWIDS, PRIMARY_KEY, SEQUENCE FROM DBA_MVIEW_LOGS WHERE MASTER = 'BASE_TABLE_NAME',三者至少两个为Y才支持FAST - 查日志表状态:
SELECT status FROM dba_objects WHERE object_name = 'MLOG$_BASE_TABLE_NAME',若为INVALID,必须重建日志 - 重建命令要显式包含分区键相关列(如果MV含分区键表达式):
CREATE MATERIALIZED VIEW LOG ON base_table WITH PRIMARY KEY, ROWID, SEQUENCE (part_key_col, col1, col2) INCLUDING NEW VALUES
索引UNUSABLE是连带现象,别和物化视图状态混为一谈
基表DROP PARTITION常导致其上的全局索引变为UNUSABLE,但这和物化视图STALENESS无关——它是独立的物理对象状态。物化视图刷新过程若用到该索引(例如基表JOIN条件走索引),就会触发ORA-01502,让人误以为是MV问题。
- 定位受影响索引:
SELECT index_name, table_name, status FROM user_indexes WHERE table_name IN (SELECT master FROM user_mview_logs) - 修复不要直接
REBUILD:先ALTER INDEX idx_name UNUSABLE,再REBUILD ONLINE,避免锁冲突 - 物化视图自身不需要索引来刷新,但基表索引失效会影响刷新SQL执行效率甚至中断,必须单独处理
STALENESS = 'UNUSABLE'状态下,所有REFRESH参数(包括ATOMIC_REFRESH、PARALLELISM)都无效,连DBMS_MVIEW.EXPLAIN_MVIEW返回的CAN_USE_LOG = 'NO'也只是结果,不是原因。必须回到COMPILE和日志重建这两个动作上,缺一不可。











