db link 必须是 public,源库需建 materialized view log 且字段匹配,mv 定义必须显式声明 refresh fast on demand,三者缺一不可,否则 fast 刷新静默退化为 complete。
db link 必须是 public 且能查真实表
物化视图刷新由 oracle 内部调度用户(如 oracle_ocm 或后台作业用户)触发,不是你当前会话,所以非 public 的 db link 一定失败。常见错误是建了 private link 后测试只跑 select * from dual@mylink,看似通了,但一刷 mv 就报 ora-02019: connection description for remote database not found 或权限不足。
- 必须用
CREATE PUBLIC DATABASE LINK,不能省略PUBLIC -
USING后的字符串要和tnsnames.ora中 alias 完全一致(大小写敏感),且监听已执行lsnrctl reload - 验证必须查真实表:
SELECT COUNT(*) FROM scott.emp@mylink,而非dual - 源库对应用户需有
SELECT权限,且账号未被ALTER USER ... ACCOUNT LOCK
源库必须建 MATERIALIZED VIEW LOG,且字段匹配
没有日志,REFRESH FAST 就不可能成立——Oracle 没地方读增量变更。日志必须建在源库,不是目标库;而且建错一个参数,后续所有 FAST 刷新都会静默退化为 COMPLETE,你根本看不出异常,直到某次刷新从 2 秒变成 5 分钟。
- 若源表有主键:建日志用
WITH PRIMARY KEY INCLUDING NEW VALUES - 若无主键:只能用
WITH ROWID,但 MV 定义中必须显式写REFRESH FAST WITH ROWID,且SELECT列里必须包含ROWID - 建完立刻查:
SELECT * FROM mlog$_emp(表名小写、前缀mlog$),确认日志表存在 - 如果 MV 查询带
WHERE deptno = 10,源表deptno字段必须有索引,否则 FAST 过滤极慢
MV 创建语句必须显式声明 REFRESH FAST ON DEMAND
REFRESH FAST 单独写是语法错误;REFRESH FORCE 会优先走 FAST,但失败就 fallback 到 COMPLETE,不报错也不提示——这是最危险的静默降级。
- 正确写法只有:
REFRESH FAST ON DEMAND(ON DEMAND不可省) - 首次建建议用
BUILD DEFERRED,避免大数据量时建表锁太久;填完数据再手动DBMS_MVIEW.REFRESH('mv_name', 'C') - 如果用了分析函数、
SYSDATE、ROWNUM或外连接,FAST 直接不可用,DBA_MVIEWS.FAST_REFRESHABLE会是NO,但建 MV 语句仍能成功 - 远程查询必须用
@dblink_name,且 DB Link 名必须和CREATE PUBLIC DATABASE LINK里定义的一致
手动刷新必须指定 method => 'F' 或 'C',不能依赖默认行为
调用 DBMS_MVIEW.REFRESH 时不传 method 参数,它就按 MV 元数据里记的默认方式走(通常是 FAST),而 FAST 失败时可能报 ORA-12008 或直接跳过,看起来像“没刷新”。
- 想强制全刷:
method => 'C',适用于日志损坏、TRUNCATE过源表等场景 - 想走增量:
method => 'F',但前提是日志完好、SNAPTIME$$水位线正常;查SELECT COUNT(*) FROM mlog$_emp WHERE SNAPTIME$$ > (SELECT LAST_REFRESH_DATE FROM DBA_MVIEWS WHERE MVIEW_NAME = 'MV_EMP')非零才算真增量 - 刷新单个 MV 必须写全名:
'SCOTT.MV_EMP',不能只写'MV_EMP',否则报ORA-00942 - 批量刷新多个:用逗号拼字符串,如
'SCOTT.MV_EMP,HR.MV_DEPT',不能用数组
真正卡住人的从来不是语法,而是三处细节没对齐:DB Link 的 PUBLIC 属性、源库日志的 INCLUDING NEW VALUES、MV 定义里那个不能少的 ON DEMAND。漏一个,FAST 就失效,你还以为是网络或性能问题。











