物化视图日志必须先于FAST刷新的物化视图创建,顺序唯一:先CREATE MATERIALIZED VIEW LOG ON base_table,再CREATE MATERIALIZED VIEW...REFRESH FAST;日志表名固定为mlog$_,超长则截断前20字符并自动加数字后缀。

物化视图日志必须先于物化视图创建
没建日志就直接建 FAST 刷新的物化视图,Oracle 会报错 ORA-12014: table does not contain a primary key 或 ORA-12052: cannot fast refresh materialized view。这不是主键缺失的问题,而是根本没日志——系统连“哪些行变了”都无从得知。
关键动作顺序只有这一种:CREATE MATERIALIZED VIEW LOG ON base_table → 再 CREATE MATERIALIZED VIEW ... REFRESH FAST。中间不能跳步,也不能倒置。
- 日志表名固定为
mlog$_,超长时截断前20字符,冲突则自动加数字后缀(如mlog$_orders1) - 日志本身不参与查询重写,只服务刷新逻辑;它不是给开发者查的,是给
DBMS_MVIEW.REFRESH内部用的 - 删除基表前,必须先删对应日志,否则报
ORA-00942: table or view does not exist(因日志依赖基表结构)
WITH PRIMARY KEY 和 WITH ROWID 的实际差异
选 PRIMARY KEY 还是 ROWID,取决于基表是否稳定有主键,以及你能否接受 UPDATE 场景下的额外开销。
WITH PRIMARY KEY 要求基表有可用主键约束,日志里会包含主键列(如 id),OLD_NEW$$ 和 DMLTYPE$$ 配合就能准确定位变更行。但注意:如果 UPDATE 修改了主键值,日志会记录两条——一条 OLD_NEW$$='o'(旧值),一条 OLD_NEW$$='n'(新值),刷新时靠这个配对识别“改了哪条”。
WITH ROWID 不依赖主键,日志里多出 M_ROW$$ 列存物理位置。优点是兼容性高;缺点是:如果基表发生 MOVE、SHRINK 或分区 SPLIT,ROWID 失效,日志里的 M_ROW$$ 就变成脏数据,后续 FAST 刷新会失败或漏数据。
- 主键稳定且不更新?优先选
WITH PRIMARY KEY - 表没主键,或主键可能被改?用
WITH ROWID,但得避开物理重组操作 - 别混用:一个日志只能有一种
WITH方式,不能同时写WITH PRIMARY KEY, ROWID
SEQUENCE 和列列表不是可选项,是增量刷新的精度控制开关
SEQUENCE$$ 列决定刷新顺序是否严格保序。WITH SEQUENCE 后,每条 DML 操作带唯一递增号,FAST 刷新时按此顺序应用变更,避免 UPDATE 和 DELETE 交错导致的状态错乱。不加它,Oracle 默认按 SNAPTIME$$ 时间戳排序,但高并发下多个事务时间戳可能相同,顺序就不可控。
显式指定列(如 WITH (col_a, col_b))意味着日志只捕获这些列的变更矢量(CHANGE_VECTOR$$),其他列修改不会触发日志记录——这能减小日志体积,但要求物化视图查询里所有 SELECT 列都必须出现在这个列表中,否则 FAST 刷新会拒绝执行。
- 业务要求强一致性(比如金融对账)?必须加
WITH SEQUENCE - 物化视图只关心几个关键字段?显式列列表 +
INCLUDING NEW VALUES可大幅降低日志 I/O - 加了列列表却忘了在物化视图定义里引用它们?刷新时报
ORA-12053: this is not a valid nested materialized view
日志表本身会成为性能瓶颈点
物化视图日志不是“静默旁观者”,它是基表 DML 的必经之路。每次 INSERT/UPDATE/DELETE,Oracle 都要往 mlog$_xxx 插一条或多条记录,相当于给每条变更加了一次额外的写操作。
实测过:一张每秒 500+ 更新的订单表,加了 WITH PRIMARY KEY, SEQUENCE 日志后,基表 DML 延迟平均增加 8~12ms,LOG FILE SYNC 等待明显上升。更麻烦的是,如果下游物化视图长期没刷新,日志表会持续膨胀,甚至撑爆表空间——因为 Oracle 不自动清理已消费的日志,全靠你手动 DBMS_MVIEW.REFRESH 或设置 NEXT 定时任务驱动。
- 日志表默认和基表同表空间,大表建议单独划出高速 SSD 表空间存放
- 监控
mlog$_xxx行数:超过基表 10% 就该检查刷新是否卡住 - 禁用
QUERY REWRITE不影响日志功能,但日志存在本身就会拖慢基表写入——这点常被忽略











