物化视图日志表(mlog$_xxx)是oracle自动生成的系统维护表,非用户业务表,其字段和行语义由刷新引擎严格约定;禁止建唯一索引,因rowid+snaptime$$不唯一、sequence$$非全局唯一、change_vector$$不可索引,且ora-01408会报错;真正需索引的是物化视图本体,而非日志表。

物化视图日志表(MLOG$_xxx)本质不是业务表
Oracle 自动生成的物化视图日志表(如 MLOG$_SALES)是系统维护的变更捕获结构,不是用户可自由建模的业务表。它的字段组合(SNAPTIME$$、SEQUENCE$$、OPERATION$$、OLD_NEW$$、CHANGE_VECTOR$$ 等)由 Oracle 内部约定,且行语义依赖于刷新引擎的解析逻辑。你不能对它加 UNIQUE 索引,因为:
- 日志表允许同一基表行在不同时间点多次变更,
ROWID+SNAPTIME$$组合也不唯一(比如同一行被 UPDATE 两次,SNAPTIME$$可能相同) -
SEQUENCE$$是会话级递增,不保证全局唯一;CHANGE_VECTOR$$是 RAW 类型,无法参与唯一性校验 - Oracle 明确禁止对日志表执行
CREATE UNIQUE INDEX,尝试会直接报ORA-01408: column list in unique index already indexed或更底层的内部错误
建唯一索引的需求其实指向错误对象
真正需要唯一索引的,从来不是日志表,而是物化视图本体(即 USER_TABLES 中那个同名对象)。例如物化视图 MV_SALES_SUM,它的查询结果要支持 REFRESH CONCURRENTLY 或优化器重写,就必须在它上面建显式 UNIQUE 或 PRIMARY KEY 索引。
- 日志表只负责“记变更”,不参与查询执行计划;索引建在它上面对查询性能、并发刷新、重写能力完全无意义
- 如果你看到别人在日志表上建了索引,大概率是误操作残留——它既不会被优化器使用,也不会被刷新引擎识别,纯属冗余
- 日志表上唯一值得建的索引,只有 Oracle 自动创建的基于
SNAPTIME$$和SEQUENCE$$的复合索引(用于快速拉取增量),用户不可干预
误建索引后可能触发的连锁问题
强行对 MLOG$_xxx 表建索引(比如用 ALTER TABLE MLOG$_SALES ADD CONSTRAINT pk_mlog PRIMARY KEY (rowid))看似成功,实则埋下隐患:
- 后续
REFRESH FAST可能失败,报ORA-12008: error in materialized view refresh path—— 因为约束修改了日志表结构,刷新引擎无法按预期解析变更向量 - 日志表被手动
ALTER后,DBA_MVIEW_LOGS视图中对应记录的STATUS可能变为INVALID,导致EXPLAIN_MVIEW返回DISABLED - 如果日志表上有用户创建的索引,
DROP MATERIALIZED VIEW LOG会失败(需先删索引),而重建日志又必须完整覆盖所有列,稍有遗漏就导致 FAST 刷新静默退化
该关注什么,而不是日志表索引
把精力从日志表移开,聚焦三个真正影响刷新和查询的关键点:
- 基表是否建了正确的日志:
CREATE MATERIALIZED VIEW LOG ON sales WITH PRIMARY KEY, ROWID, SEQUENCE(sale_id, amount, sale_date) INCLUDING NEW VALUES—— 漏掉ROWID或关键业务列,FAST 就废了 - 物化视图本体是否有显式唯一索引:比如
CREATE UNIQUE INDEX idx_mv_sales_sum ON mv_sales_sum (month_key, product_id),且所有列NOT NULL - 统计信息是否刷新:
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCHEMA', tabname => 'MV_SALES_SUM', cascade => TRUE)—— 不带cascade => TRUE,索引统计就是空的











