基表变更不会自动触发物化视图刷新,需显式配置REFRESH ON COMMIT或结合DBMS_SCHEDULER定时刷新;ON COMMIT要求基表有主键且满足快速刷新限制,刷新在commit瞬间同步执行;ON DEMAND+调度器更适用于高并发场景,但依赖物化视图日志存在且未被purge。
基表变更本身不会自动触发物化视图刷新,必须显式配置 on commit 或结合调度机制才能实现“实时响应”。直接改基表数据(哪怕 commit 了),若物化视图没设 refresh on commit,就不会动。
REFRESH ON COMMIT 是唯一真正“基表一提交就刷”的方式
它依赖基表有主键或唯一约束,且物化视图定义必须满足快速刷新限制(比如不能含分析函数、子查询不能多层嵌套)。
- 创建时必须带
REFRESH ON COMMIT,例如:CREATE MATERIALIZED VIEW mv_emp REFRESH ON COMMIT AS SELECT * FROM emp; - 基表
emp上必须存在主键(ALTER TABLE emp ADD PRIMARY KEY (empno);),否则建视图会报ORA-12014 - 刷新发生在事务 commit 的瞬间,不是后台异步;如果 commit 失败,刷新也不发生
- 多个会话并发修改同一基表时,
ON COMMIT刷新可能引发锁等待,大表慎用
ON DEMAND + DBMS_SCHEDULER 定时拉取是更可控的“准实时”方案
当基表变更频率高、但业务允许秒级延迟时,用调度器比 ON COMMIT 更稳定,也避开锁风险。
- 先确保物化视图支持快速刷新:
SELECT FAST_REFRESHABLE FROM USER_MVIEWS WHERE MVIEW_NAME = 'MV_NAME';返回YES才能用F模式 - 创建调度任务,每 30 秒检查一次(注意太密可能压垮日志消费):
BEGIN DBMS_SCHEDULER.CREATE_JOB(... job_action => 'BEGIN DBMS_MVIEW.REFRESH(''SCOTT.MV_NAME'', ''F''); END;'); END; - 物化视图日志必须存在且未被 purge,否则
F刷新静默跳过——查USER_MVIEW_LOGS.LAST_PURGE_DATE和LOG_TABLE行数是否增长 - 不要用
NEXT_DAY(SYSDATE, 'MONDAY')这类表达式做高频调度,Oracle 解析开销大;改用SYSDATE + 30/86400
DBMS_MVIEW.REFRESH('MV', 'F') 不等于“立刻同步”,它只消费已有日志
这是最常被误解的一点:快速刷新不是监听 DML 实时流,而是批量读取物化视图日志表(如 MLOG$_T_ORDER)里的记录并应用。
- 如果基表刚执行了
INSERT,但还没 commit,日志表里就没有对应行,REFRESH('F')就什么也不做 - 如果日志表被其他作业清空(
DBMS_MVIEW.PURGE_LOG),或LAST_PURGE_DATE比你期望的更新时间还晚,那这次刷新就只能“假装成功” - 查日志是否有待消费记录:
SELECT COUNT(*) FROM MLOG$_T_ORDER WHERE SNAPTIME$$ —— 若为 0,F刷不出来东西 - 调试用:
EXEC DBMS_MVIEW.EXPLAIN_MVIEW('MV_NAME');然后看MVIEW_EXCEPTIONS表,里面会写明为什么无法快速刷新(比如缺少主键、表达式不支持等)
真正难的不是写那句 REFRESH,而是确认日志有没有、有没有被截断、有没有权限消费、以及物化视图定义本身是否还合法——这些状态全得手动验证,Oracle 不会主动告诉你缺哪一环。











