merge不能单独完成增量同步,必须搭配delete语句处理源端已删除记录,且依赖源表中可靠的时间戳字段(如last_modified),该字段需在每次insert和update时显式赋值,建表优先选用timestamp类型,并通过日志表持久化管理上次抽取时间。
merge 不能单独完成增量同步——它不处理源端已删除的记录,必须搭配 delete 语句补全逻辑,且前提是源表有可靠的时间戳字段(如 last_modified 或 create_time)。
时间戳字段必须可信赖,否则增量会漏或重
Oracle 的 TIMESTAMP 和 DATE 类型本身不会自动更新;业务写入或更新数据时,必须显式给时间戳字段赋值(比如 SYSDATE 或 CURRENT_TIMESTAMP)。常见错误是只在 INSERT 时设值,UPDATE 却没改,导致后续抽取查不到变更。
- 建表时建议用
TIMESTAMP,精度更高,尤其当并发更新频繁、秒级冲突可能时 - 如果业务层无法保证每次
UPDATE都更新时间戳,就得在表上加触发器(BEFORE UPDATE),强制刷新last_modified - 避免用
SYSDATE直接拼字符串比较,应统一用TO_DATE或TO_TIMESTAMP转换,防止格式不一致导致过滤失效
存储过程里怎么写“上次抽取时间”管理逻辑
不能硬编码时间点,得把上次成功抽取的截止时间存起来——通常建一张日志表(如 ETL_LOG_DRAGON_ALERT),按表名记录 etlbegintime 和 etlendtime。每次执行前查最新 etlendtime,作为本次抽取的起点。
- 首次运行时,
etlendtime为空,需设一个合理初值(比如TO_DATE('2020-01-01', 'YYYY-MM-DD')) - 抽取完成后,必须更新日志表的
etlendtime为本次最大时间戳(不是SYSDATE!),否则下次会漏掉刚好在边界上的记录 - 建议用
SELECT MAX(last_modified) INTO v_max_ts FROM src_table WHERE last_modified > v_last_end_time获取真实上限,再写入日志
MERGE + DELETE 才算完整增量同步
MERGE 只能 upsert(插入或更新),对源端已删但目标端还留着的脏数据无能为力。必须额外执行 DELETE,条件是目标表中存在、但源表里对应时间戳范围内已不存在的记录。
- 典型写法:
DELETE FROM target_t WHERE id IN (SELECT id FROM target_t t WHERE NOT EXISTS (SELECT 1 FROM source_t s WHERE s.id = t.id AND s.last_modified > v_last_end_time)) - 注意:这个
DELETE范围不能扩大到全表,否则会误删历史归档数据;限定在“本次及之前增量窗口内”的记录更安全 - 性能敏感场景下,
DELETE前先建临时表缓存待删id列表,避免子查询反复扫描大表
ORA_ROWSCN 不适合直接替代时间戳做增量
虽然 ORA_ROWSCN 看似能反映行级变更,但它默认精度是数据块级(block-level),同一块内多行 ORA_ROWSCN 相同;即使建表时加了 ROWDEPENDENCIES,也依赖 SCN 转时间戳(SCN_TO_TIMESTAMP),而 SCN 归档保留期有限,跨天/跨备份可能查不到对应时间。
- 生产环境用
ORA_ROWSCN做增量,必须确认归档日志保留策略和SCN_TO_TIMESTAMP可查范围 - 时间戳方式更可控、可审计,调试时能直接
SELECT * FROM src WHERE last_modified > ...验证数据范围 - 除非源表完全无法加字段、又没触发器权限,否则别轻易切到
ORA_ROWSCN
真正容易被忽略的是时间戳字段的业务一致性——它不是数据库自动维护的元数据,而是业务逻辑的一部分。一旦上游应用漏更新,下游同步就不可逆地失真,日志表里的时间点再准也没用。











