oracle 19c物化视图不支持实时事件驱动的“数据订阅”,本质是依赖mlog$_日志+手动或定时调用dbms_mview.refresh实现被动轮询式增量同步;真正记录dml变更的是物化视图日志表,而非物化视图本身。
oracle 19c 中无法直接用物化视图实现通用“数据订阅”功能——它不是消息队列,也不提供变更事件推送能力;所谓“订阅”,本质是靠物化视图日志(mlog$_)+ 定时/手动 dbms_mview.refresh 拉取增量,属于被动轮询式同步,不是实时事件驱动。
物化视图日志才是真正的增量源,不是物化视图本身
很多人误以为刷新物化视图就是在“订阅数据”,其实真正记录 DML 变更的是底层的物化视图日志表(如 MLOG$_emp)。物化视图只是消费端,日志才是生产端。
-
MLOG$_表里有DMLTYPE$$(I/U/D)、OLD_NEW$$(O/N/U)、SEQUENCE$$(保证顺序)、CHANGE_VECTOR$$(标记改了哪些字段),这些才是可被解析的增量信号 - 只要源表已建合规日志(含
INCLUDING NEW VALUES和显式SEQUENCE()),哪怕不建物化视图,你也能直接查MLOG$_表做自定义解析——比如用 Java 或 Python 定时轮询并投递到 Kafka - 注意:
MLOG$_不自动清理,长期运行必须配DBMS_MVIEW.PURGE_LOG或手工DELETE,否则日志膨胀会拖慢刷新甚至阻塞 DML
REFRESH FAST 必须显式触发,不会自动“推送”
即使所有条件都满足(DB Link 通、日志全、MV 定义合规),REFRESH FAST 也不会在源表变更后自动执行——它只响应你调用 DBMS_MVIEW.REFRESH('mv_name', 'F') 或配置了 ON COMMIT(后者不支持跨库)。
-
ON DEMAND是默认且唯一支持跨库的模式,意味着你得自己写调度(如 DBMS_SCHEDULER 或外部 cron)定期调用刷新 - 不要依赖
REFRESH FORCE来“兜底”:它静默降级为COMPLETE时无报错,只会在V$MVREFRESH或 trace 日志里留下fastrefreshable = FALSE的线索 - 验证是否真走 FAST:刷新后立刻查
SELECT * FROM TABLE(DBMS_MVIEW.EXPLAIN_MVIEW('mv_name')),确认fastrefreshable列值为TRUE,且msg为空
子查询、聚合、分区表会直接关闭 FAST 路径
一旦物化视图 SQL 中出现 EXISTS、IN、ROWNUM、SYSDATE 或非主键聚合(如 GROUP BY deptno 但没包含 empno),Oracle 就彻底放弃 FAST 刷新,连日志都不看。
- 常见陷阱:
SELECT * FROM emp WHERE deptno IN (SELECT deptno FROM dept)看似简单,但子查询导致DBMS_MVIEW.EXPLAIN_MVIEW返回fastrefreshable = FALSE - 替代方案不是“优化 SQL”,而是重写为等价 JOIN,并确保两个基表都有完整日志(含 JOIN 列、
INCLUDING NEW VALUES、WITH PRIMARY KEY) - 分区表别指望“分区级增量”:Oracle 19c 的 FAST 刷新只认行级日志,不管数据在哪个分区;分裂或移动分区可能使
ROWID失效,所以必须用WITH PRIMARY KEY日志
真正能落地的“订阅”,是把 MLOG$_ 当作变更日志表来读,而不是依赖物化视图刷新机制。后者太重、太隐晦、太容易静默退化——稍有配置偏差,你就只能看着刷新耗时从秒级涨到分钟级,却找不到报错。











