Oracle增量同步必须开启补充日志,推荐数据库级最小日志加主键级补充日志;物化视图日志轻量但能力有限,仅适用于低频稳定场景;LogMiner最通用但需手动管理SCN位点与日志解析,且下游写入必须幂等。
Oracle端必须开启补充日志才能捕获DML变更
oracle默认不记录完整的行变更信息,update 只记被改的列,delete 不带旧值,insert 没有前镜像——这对增量同步是致命缺陷。必须显式启用补充日志(supplemental logging),否则哪怕开了dbms_logmnr或物化视图日志,你也拿不到完整变更数据。
实操建议:
- 执行
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;启用数据库级最小补充日志(必需) - 对目标表单独加主键级补充日志:
ALTER TABLE schema.table_name ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;(推荐,比ALL日志更轻量) - 确认生效:
SELECT SUPPLEMENTAL_LOG_DATA_MIN, SUPPLEMENTAL_LOG_DATA_PK FROM V$DATABASE;返回YES才算到位 - 注意:RAC环境下需在所有实例上执行;归档模式不是强制要求,但
LOGMNR解析归档日志时必须开启
物化视图日志(MLOG$)适合低频、表结构稳定场景
物化视图日志本质是Oracle自动维护的一张变更快照表(如MLOG$_EMP),它只记录ROWID、操作类型(DMLTYPE$$)、时间戳(SNAPTIME$$)和必要键值,不存完整新/旧值。它轻量、无需解析重做日志,但能力有限。
使用前提与限制:
- 目标表必须有主键或唯一约束(否则建日志会报
ORA-12013) - 建日志语句必须显式指定字段:
CREATE MATERIALIZED VIEW LOG ON schema.table_name WITH PRIMARY KEY, ROWID, SEQUENCE(col1,col2) INCLUDING NEW VALUES; - .NET中轮询时读
MLOG$_xxx表,处理完后必须调用DBMS_MVIEW.REFRESH_MVIEWS或清空日志(靠SNAPTIME$$标记位),否则重复消费 - 不支持
TRUNCATE、DDL变更、LOB字段变更——这类操作不会写入MLOG$
LogMiner是.NET对接Oracle增量最通用但最重的方案
DBMS_LOGMNR 是Oracle官方提供的重做日志解析接口,能还原出完整的SQL_REDO/SQL_UNDO,支持所有DML+部分DDL,是真正意义上的“变更捕获”。但它不是开箱即用的服务,需要.NET主动驱动解析流程。
关键实操点:
- 先添加日志文件:
DBMS_LOGMNR.ADD_LOGFILE,注意路径必须是Oracle可读的(非.NET进程路径),且建议用归档日志避免在线日志覆盖丢失 - 启动LogMiner时务必设
OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG,否则查不到对象名,只有OBJECT_ID - .NET中通过
OracleCommand查V$LOGMNR_CONTENTS,过滤OPERATION IN ('INSERT','UPDATE','DELETE')和SEG_OWNER = 'XXX',注意SCN顺序不代表提交顺序,要按COMMIT_SCN分组 - 性能瓶颈明显:单次解析不宜跨多天日志;建议按小时切片,用
STARTSCN/ENDSCN控制范围;频繁调用START_LOGMNR开销大,应复用会话
.NET客户端需自行管理位点(SCN或时间戳)和幂等写入
Oracle本身不提供“已同步到哪”的状态托管,所有位点(SCN、SNAPTIME$$、自定义时间戳)都得.NET自己存、自己读、自己校验。这是最容易出错的一环。
- 位点存储不能放在内存里——进程重启就丢;推荐用一张小表(如
SYNC_CHECKPOINT)存TABLE_NAME、CURRENT_SCN、LAST_UPDATE_TIME - 每次同步前先查位点,再拉取变更,成功写入下游后,**再更新位点**;失败则重试原位点,避免跳变
- 下游写入必须幂等:
UPSERT用主键或MERGE,DELETE加条件(如WHERE UPDATE_TIME > :last_sync_time),防止重复执行导致数据错乱 - 物化视图日志方案中,
SNAPTIME$$ = '00000000000000'表示未处理,但并发多个消费者时需加行锁或应用层分布式锁,否则MLOG$会被多线程重复读
真正麻烦的从来不是连上Oracle或者跑通第一条UPDATE,而是当某天归档日志被清理、物化视图日志因DDL失效、或者位点表被人手动改了——这些边界情况不会报错,只会让后续增量慢慢偏移,直到某天发现少了三天数据。











