物化视图日志使每条DML稳增同步写入开销,实测10万行插入从0.21秒升至3.73秒(+3.52秒),核心因日志INSERT与原DML同事务绑定、需等待redo落盘及索引更新完毕。

物化视图日志会让每条DML多出多少毫秒
不是“偶尔卡顿”,而是每条INSERT/UPDATE/DELETE都稳稳增加同步写入开销。实测显示:无日志时10万行插入耗时约0.21秒;加物化视图日志后升至3.73秒;若再启用FAST刷新,直接涨到8.98秒。核心损耗来自日志表的同步INSERT——它和原DML绑定在同一事务中,必须等redo落盘、索引块更新完毕才能返回。
关键判断依据:V$SESSION_EVENT里持续出现db file sequential read(日志索引读)或log file sync(redo写等待),V$SQL中对应DML语句的elapsed_time/executions比基线高3–10倍,基本可确认是日志拖慢。
怎么定位日志表IO是否成瓶颈
物化视图日志表(如MLOG$_ORDERS)本质是普通堆表,性能完全取决于所在表空间的IO能力。常见坑是混放在USERS或SYSTEM表空间,这些地方往往用手动段管理(MANUAL)、无AUTOALLOCATE、共享磁盘LUN。
- 查日志表位置:
SELECT table_name, tablespace_name FROM user_tables WHERE table_name LIKE 'MLOG$%' - 查表空间属性:
SELECT extent_management, allocation_type FROM dba_tablespaces WHERE tablespace_name = 'XXX' - IO争用信号:
V$SEGMENT_STATISTICS中MLOG$%表的physical reads或gc cr blocks received异常高
优先迁移到LOCAL + AUTOALLOCATE的专用SSD表空间,能立竿见影降低单次日志写入延迟。
冗余索引会让DML变慢几倍
Oracle默认为日志表建两个必要索引:I_MLOG$_xxx(ROWID主键)和I_SNAP$_xxx(加速SNAPTIME$$查询)。但很多人额外加ON (sequence$$)或ON (snaptime$$, dmltype$$)——这反而让每次INSERT都要同步更新多个索引块。
实测:单条日志插入从0.2ms升至1.5ms+,OLTP场景下极易触发latch: cache buffers chains等待。检查方法:
SELECT index_name, column_name FROM user_ind_columns WHERE table_name LIKE 'MLOG$%' ORDER BY index_name
只保留Oracle自建的两个索引,其余一律DROP INDEX。别碰ROW MOVEMENT和COMPRESS FOR OLTP——它们对日志表毫无收益,只会拖慢INSERT。
分区表上建日志后,DML性能下降是否与分区数有关
无关。性能损耗主要来自日志表本身的写入路径,而不是基表有多少个分区。但有一个间接影响:如果基表是INTERVAL分区且高频新增分区,而日志表未及时收集统计信息,优化器可能误判日志扫描代价,导致DBMS_MVIEW.REFRESH时执行计划退化,反过来又会拉长刷新窗口——从而延长日志表被大量写入的时间段,放大感知到的DML延迟。
所以必须定期跑:EXEC DBMS_STATS.GATHER_TABLE_STATS(user, 'MLOG$_YOUR_TABLE'),尤其在批量刷新前后。否则SNAPTIME$$范围扫描可能从索引范围扫描退化为全表扫描,连带让后续DML的日志写入排队更久。
最易被忽略的是:日志表统计信息过期不会报错,但会让整个快速刷新链路不可预测——DML慢只是表象,根子在刷新任务卡住后日志堆积。



















