物化视图FAST刷新失败主因是依赖链断裂或隐式条件不满足,需用DBMS_MVIEW.EXPLAIN_MVIEW定位具体原因,检查日志结构、基表约束及SQL中非确定性函数。

物化视图刷新失败,90% 以上不是语法写错,而是依赖链断了或隐式条件不满足——Oracle 不报具体原因,只静默退化为 COMPLETE 或抛 ORA-12008/ORA-12052,必须靠 DBMS_MVIEW.EXPLAIN_MVIEW 把内部判断翻出来。
查不到错误原因?先跑 DBMS_MVIEW.EXPLAIN_MVIEW
别猜“是不是日志没建”或“是不是写了子查询”,直接执行:EXEC DBMS_MVIEW.EXPLAIN_MVIEW('MV_NAME');
结果默认写入 PLAN_TABLE。重点查这三列:
-
CAPABILITY_NAME = 'REFRESH_FAST'对应的POSSIBLE值:若为'N',说明 FAST 刷新被彻底禁用 -
MSGTXT字段:人话提示,比如"materialized view log does not exist on table T1"或"complex SQL: outer join with OR in WHERE clause" -
MSGNO编号:2005=缺日志、2012=漏ROWID、2025=聚合不合规、2031=外连接含OR或函数
基表日志存在 ≠ 日志可用
很多问题表面是 SQL 写法不对,实际是日志结构已失效。检查三件事:
-
SELECT LOG_TABLE, ROWIDS, PRIMARY_KEY FROM USER_MVIEW_LOGS WHERE MASTER = 'YOUR_TABLE':其中ROWIDS必须为'Y',否则 FAST 无法用ROWID定位行 -
SELECT COLUMN_NAME FROM USER_MVIEW_LOG_FILTERS WHERE LOG_TABLE = 'MLOG$_YOUR_TABLE':所有 JOIN 列、WHERE 条件列、GROUP BY 列都必须出现在这里;新增列没进SEQUENCE()就等于没记录变更 -
SELECT CAN_USE_LOG FROM USER_MVIEWS WHERE MVIEW_NAME = 'MV_NAME':返回'NO'说明日志链已断,刷新必然退化
基表 DDL 变更后日志自动失效
基表加了 NOT NULL 列、删了主键、改了约束类型,旧日志立刻不可用,但 Oracle 不提示。典型表现是:刷新突然变慢、STALENESS 长期为 'STALE'、CAN_USE_LOG = 'NO'。
- 查基表约束状态:
SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, STATUS FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'YOUR_BASE_TABLE' AND CONSTRAINT_TYPE IN ('P', 'U') - 确认日志是否覆盖新增列:
SELECT COLUMN_NAME FROM USER_MVIEW_LOGS l JOIN USER_MVIEW_LOG_FILTERS f ON l.LOG_TABLE = f.LOG_TABLE WHERE l.MASTER = 'YOUR_TABLE' - 若缺失列,不能只
ALTER日志——必须重建:DROP MATERIALIZED VIEW LOG ON your_table,再用完整语句重建,例如:CREATE MATERIALIZED VIEW LOG ON t WITH ROWID, SEQUENCE(col1,col2) INCLUDING NEW VALUES
非确定性函数和子查询直接禁用 FAST
Oracle 19c 起内核级禁止含以下内容的 FAST 刷新,配置或权限无法绕过:
-
EXISTS/NOT EXISTS、IN (subquery)、ANY/ALL - 非关联子查询(如
WHERE col > (SELECT MAX(x) FROM t)) -
SYSDATE、USER、SYSGUID()、DBMS_RANDOM.VALUE等运行时才确定值的表达式 - 即使
EXISTS可改写为INNER JOIN,NOT EXISTS也必须拆成UNION ALL+ 主键关联,且两张基表日志都得覆盖 JOIN 列和INCLUDING NEW VALUES
最容易被忽略的是:物化视图定义里用了 SYSDATE,EXPLAIN_MVIEW 会标 UNUSABLE,但你可能根本没去查——它不会在创建时报错,只在第一次刷新时失败。


















