物化视图日志(MLOG$_表)缺乏关键列索引及统计信息过期,导致基表DML锁争用和全表扫描;刷新进程共享回滚段加剧阻塞;需同步创建SNAPTIME$$/SEQUENCE$$组合索引并更新基表与日志表统计信息。
刷新期间基表查询变慢,核心原因是物化视图日志(mlog$_ 表)被大量写入且缺乏有效索引,导致基表 dml 操作在日志维护阶段出现锁争用或全表扫描。
物化视图日志成为基表 DML 的性能瓶颈
只要基表启用了快速刷新(REFRESH FAST),所有 INSERT/UPDATE/DELETE 都会同步写入对应的 MLOG$_xxx 表。这个日志表默认只有主键索引(I_MLOG$_xxx),但若缺失关键列上的索引(如 SEQUENCE$$、SNAPTIME$$ 或分区键列),后续的物化视图刷新进程在读取日志时就会触发 TABLE ACCESS FULL,而该扫描过程会与基表 DML 争抢日志表的缓冲区和 I/O 资源。
- 常见现象:基表上执行
UPDATE语句明显卡顿,AWR 中看到大量enq: TX - row lock contention或db file sequential read等待在MLOG$_表上 - 验证方式:查
SELECT LOG_TABLE FROM USER_MVIEWS WHERE MVIEW_NAME = 'MV_NAME'定位日志名,再运行EXPLAIN PLAN FOR SELECT * FROM MLOG$_BASE_TBL WHERE SNAPTIME$$ > ...,看是否走索引 - 修复动作:对日志表显式创建组合索引,例如
CREATE INDEX idx_mlog_snap_seq ON MLOG$_BASE_TBL(SNAPTIME$$, SEQUENCE$$) TABLESPACE idx_ts
刷新进程与基表 DML 共享同一回滚段
当调用 DBMS_MVIEW.REFRESH 且未指定 atomic_refresh => FALSE 时,Oracle 默认以单事务方式执行(尤其 COMPLETE 刷新)。这个大事务会持续占用回滚段,导致基表上的并发 DML 因 undo 空间争用而阻塞。
- 典型表现:基表 DML 出现
ORA-01555: snapshot too old或长时间等待enq: US - contention - 参数影响:
atomic_refresh => TRUE(默认)强制 TRUNCATE + INSERT,需全程持有表级锁;atomic_refresh => FALSE改为分批 MERGE 提交,降低锁粒度 - 必须配套:设
rollback_seg => 'RB_LARGE'指向专用大回滚段,避免与其他业务混用
基表统计信息过期引发刷新 SQL 执行计划错误
物化视图刷新本质是 Oracle 自动生成一段 SQL(比如 MERGE into MV),它依赖基表和日志表的统计信息来选择访问路径。如果基表刚经历大批量 DML 但没收集统计信息,优化器可能误判日志表大小,选择嵌套循环连接而非哈希连接,或对 MLOG$_ 表做全表扫描——这会直接拖慢刷新速度,并反过来加剧基表 DML 的等待。
- 检查点:查
DBA_TAB_STATISTICS中基表和对应MLOG$_表的LAST_ANALYZED时间是否滞后于最近一次批量操作 - 刷新前必做:
DBMS_STATS.GATHER_TABLE_STATS必须覆盖基表 + 日志表,且对分区表加GRANULARITY => 'PARTITION' - 别漏日志表:日志表不是自动维护对象,
DBMS_STATS.GATHER_SCHEMA_STATS不会包含它,必须显式指定
真正难处理的是日志表索引和统计信息的协同问题:索引建了但统计没更新,或统计更新了但索引列不匹配查询谓词,都会让刷新 SQL 在日志表上走歪。这两者必须一起验证,不能只改一个。


















