物化视图FAST刷新必须依赖主键:源表需有PRIMARY KEY约束,物化视图日志须显式指定WITH PRIMARY KEY;跨库同步须配置有效DBLINK并授权SELECT权限;创建时必须使用ON PREBUILT TABLE;推荐用DBMS_SCHEDULER替代JOB_QUEUE_PROCESSES调度刷新。

物化视图同步必须有主键,否则 REFRESH FAST 会失败
Oracle 的 REFRESH FAST 模式依赖基表上的变更日志(MATERIALIZED VIEW LOG),而该日志默认只支持基于主键或 ROWID 的增量捕获。如果源表没主键,建日志时虽不报错,但后续创建物化视图时指定 FAST 会直接报 ORA-12015: cannot create a fast refresh materialized view from a non-replicated table。
- 必须先在源库执行
ALTER TABLE your_table ADD CONSTRAINT pk_your_table PRIMARY KEY (id);(字段需非空且唯一) -
WITH PRIMARY KEY是显式要求,建日志时不能省略:CREATE MATERIALIZED VIEW LOG ON your_table WITH PRIMARY KEY; - 若实在无法加主键,可改用
WITH ROWID,但目标库表必须用ON PREBUILT TABLE,且跨库时ROWID无效——所以异地同步基本只能选主键方案
DBLINK 连接必须能双向验证,且账号要有 SELECT 权限
外网库建的 DBLINK 不只是“能连上”,还必须让目标物化视图能稳定读取源表。常见卡点是:源库用户没被授权、网络策略拦截、tnsnames.ora 配置未同步到目标库实例。
- 源库需显式授权:
GRANT SELECT ON schema.table_name TO dblink_user;(注意不是GRANT SELECT ANY TABLE,最小权限原则) -
DBLINK创建后,务必在目标库执行测试查询:SELECT COUNT(*) FROM your_table@your_dblink;,不能只测SELECT 1 FROM DUAL@your_dblink - 若用的是 Oracle 12c+,建议用
PUBLIC DATABASE LINK并配GLOBAL_NAMES=TRUE,避免因数据库名大小写或域名不匹配导致刷新时报ORA-02019: connection description for remote database not found
跨库物化视图必须用 ON PREBUILT TABLE,否则表结构不可控
直接用 CREATE MATERIALIZED VIEW mv_name AS SELECT ... 会让 Oracle 自动建表,但该表的字段顺序、NULL/NOT NULL 属性、索引、约束全由 Oracle 决定,后续 DDL 维护困难,且一旦删 MV,表就跟着消失——这在生产环境极危险。
- 先在目标库手工建表:
CREATE TABLE your_table AS SELECT * FROM your_table@your_dblink WHERE 1=0; - 再创建物化视图时绑定已有表:
CREATE MATERIALIZED VIEW your_table ON PREBUILT TABLE REFRESH FAST ON DEMAND AS SELECT * FROM your_table@your_dblink; - 首次必须手动完全刷新:
EXEC DBMS_MVIEW.REFRESH('YOUR_TABLE', 'C');,否则表里没数据 - 之后才能安全切到
FAST刷新,且可随时单独操作该表(如加索引、分区),不影响 MV 逻辑
定时刷新别依赖 JOB_QUEUE_PROCESSES,改用 DBMS_SCHEDULER
老教程里用 ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 20 开启 job 队列,但这在 RAC 或多租户环境下不稳定,且 DBMS_JOB 已被 Oracle 标记为 deprecated。实际中更可靠的是调度器作业。
- 确认调度器启用:
SELECT VALUE FROM V$PARAMETER WHERE NAME = 'job_queue_processes';—— 值 > 0 即可,无需设具体数字 - 创建调度作业:
BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'mv_refresh_job', job_type => 'PLSQL_BLOCK', job_action => 'BEGIN DBMS_MVIEW.REFRESH(''YOUR_TABLE'', ''F''); END;', start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0;', enabled => TRUE); END; - 检查作业状态:
SELECT job_name, state, last_start_date, next_run_date FROM DBA_SCHEDULER_JOBS WHERE job_name = 'MV_REFRESH_JOB';
真正麻烦的不是语法,而是源库物化视图日志积压和网络抖动导致的刷新中断——每次失败后,DBA_MVIEWS.LAST_REFRESH_DATE 和 DBA_MVIEW_LOGS.LOG_OWNER 必须人工核对,否则增量数据就断链了。


















