mlog$_表堆积需先查count(*)确认是否远超基表变更量,再比对dba_mview_logs与dba_objects的object_id是否一致,id不一致说明日志失联,fast刷新将静默退化或报ora-00942。

查日志表是否真在堆积,别只看告警
归档日志暴增或刷新卡住,90% 源于 MLOG$_ 表写入但无人消费。先确认是不是它在疯长:SELECT COUNT(*) FROM MLOG$_your_master_table。如果结果远超基表日常变更量(比如基表一天改几百行,日志却有 80 万条),基本就是它了。
再查元数据是否脱钩:SELECT master_object_id FROM dba_mview_logs WHERE log_table = 'MLOG$_YOUR_TABLE',对比SELECT object_id FROM dba_objects WHERE owner = 'SCHEMA' AND object_name = 'YOUR_TABLE'。ID 不一致说明日志已“失联”,即使表存在,FAST 刷新也会静默退化或报 ORA-00942。
- 若
MLOG$_表查不到或status是INVALID,说明物理丢失或依赖失效,不能只TRUNCATE,得重建日志 - 大小写敏感场景下,用
SELECT object_name FROM dba_objects WHERE UPPER(object_name) LIKE 'MLOG%YOUR_TABLE%'避免漏掉带引号的变体 -
SELECT MAX(snaptime$$) FROM MLOG$_your_master_table和当前时间差值若超过undo_retention(如差 45 分钟而undo_retention=900),后续 FAST 刷新大概率触发ORA-01555
验证 FAST 刷新是否真能走通,别信定义里的默认值
物化视图定义里写了 REFRESH FAST ON COMMIT,不代表它真能走 FAST。Oracle 会在内部校验后静默 fallback 到 COMPLETE,而你可能根本没察觉——直到卡死或报 ORA-12008。
必须执行:EXEC DBMS_MVIEW.EXPLAIN_MVIEW('YOUR_MV_NAME'),然后查 MVIEW_EXCEPTIONS 表:SELECT capability_name, possible, msgtxt FROM mv_capabilities_table WHERE statement_id = 'QSMQT_EXPLAIN_MVIEW'。
- 若
fast_refreshable返回UNDEFINED或DIRLOADDML,说明定义本身不满足 FAST 条件(如含AVG()、SYSDATE、未覆盖 JOIN 字段) -
REFRESH_FROM_LOG_AFTER_ANY = 'DISABLED'且msgtxt提示缺失主键或索引,说明基表结构已变更(如删了唯一索引),FAST 路径已被破坏 -
REFRESH_FROM_LOG_AFTER_INSERT = 'DISABLED'通常指向日志字段不全,比如新增列没加进SEQUENCE()括号里
手动试一次 FAST 刷新并抓底层错误,别反复重跑
ORA-12008 是个“占位符错误”,真正的问题藏在它下面。直接执行 BEGIN DBMS_MVIEW.REFRESH('YOUR_MV_NAME', 'F'); END; 报错后,你看到的只是表层信号灯。
必须提前开 trace:ALTER SESSION SET EVENTS '10046 trace name context forever, level 12',失败后去 USER_DUMP_DEST 找最新 trace 文件,搜索 ORA- —— 真正的约束冲突、字段超长、临时表空间不足,全在那里。
- 同时查
V$SESSION_LONGOPS:SELECT * FROM V$SESSION_LONGOPS WHERE OPNAME LIKE '%refresh%',看卡在哪条 SQL(如停在MERGE INTO MV_XXX) - 若 trace 里出现
ORA-01706(表达式太长)或ORA-01652(无法扩展临时段),说明问题不在日志或权限,而在 MV 查询本身或资源配额 - 别在没关
atomic_refresh => TRUE的情况下反复试,这会持续占用 undo 并加剧锁竞争
清理积压日志并重建链路,别直接 TRUNCATE TABLE MLOG$_
日志表积压不是靠清空就能解决的。直接 TRUNCATE TABLE MLOG$_xxx 会破坏数据字典,后续建同名日志可能报 ORA-12083 或 ORA-12003。
安全做法是先停作业:EXEC DBMS_SCHEDULER.DISABLE('MV_REFRESH_JOB_NAME'),再用官方接口清理:EXEC DBMS_MVIEW.PURGE_LOG('your_master_table')。它比 TRUNCATE 安全,会同步更新内部 snaptime$$ 标记。
- 重建日志前,务必确认 MV 定义支持 FAST——否则建了也是摆设;
EXPLAIN_MVIEW输出中RECOMMENDATION若为AGGREGATE或JOIN,说明必须重构 MV 定义 - 重建日志时只包含 MV SQL 实际引用的列,
WITH ROWID, SEQUENCE(col1, col2) INCLUDING NEW VALUES,避免冗余字段放大日志体积 - 补建后立刻手动执行一次
DBMS_MVIEW.REFRESH('YOUR_MV_NAME', 'F'),否则日志不会重新开始记录新变更
真实难点往往卡在“日志表存在、基表存在、权限也给了”,但 OBJECT_ID 关联断裂或 SEQUENCE$$ 时间戳错位这种元数据层面的细节。这些地方一出问题,Oracle 就不报明确错误,而是悄悄降级、卡住、撑爆归档——必须一层层往下挖,而不是在表面参数上反复调。











