定时校验不能依赖DBMS_COMPARISON,因其非后台服务且缺乏自动触发、清理和告警能力;应采用Oracle原生物理层检查(如v$archived_log、v$log_history等)封装为脚本,配合时间过滤与抽样哈希法实现可追溯、低干扰的定时一致性校验。
定时校验不能依赖 DBMS_COMPARISON 自动跑
dbms_comparison 不是后台服务,它不支持“自动触发+自动清理+自动告警”,每次调用都得手动建 comparison、执行 compare、查 dba_comparison_row_dif、删 comparison。硬塞进 crontab 或 dbms_scheduler 里,极易因锁表(select for update)、对象不支持(lob/分区表)、或 scan_id 未清理导致后续失败。dbms_comparison.create_comparison 和 dbms_comparison.compare 必须成对使用,漏掉 dbms_comparison.drop_comparison 会残留元数据,下次同名 comparison 直接报 ora-42381。
真正能定时的只有物理层验证动作
主备一致性校验的定时能力,必须落在 Oracle 原生可脚本化的物理检查上,而非逻辑比对。这些操作可封装为 SQL 脚本 + OS 脚本组合,由 crontab 或 DBMS_SCHEDULER 驱动:
- 查
v$archived_log中最近 1 小时内APPLIED = 'NO'的连续数量:超 5 个就写入告警日志 - 比对主备
v$log_history的MAX(SEQUENCE#)差值:差 ≥ 3 就触发邮件通知 - 查
v$archive_gap:有返回行立即记录并告警 - 查
v$managed_standby中PROCESS = 'MRP0'的SEQUENCE#是否 60 秒内无变化
注意:所有查询必须加时间过滤(如 WHERE FIRST_TIME > SYSDATE - 1/24),否则在大归档量库上全扫 v$archived_log 会拖慢整个实例。
关键表行级校验只能抽样,且必须避开业务高峰
如果真要定时做行级核对(比如每晚 2 点对订单表抽样),别用 DBMS_COMPARISON,改用轻量哈希法,绕过锁和对象限制:
- 主备分别执行:
SELECT COUNT(*), DBMS_CRYPTO.HASH(UTL_RAW.CAST_TO_RAW(LISTAGG(NVL(TO_CHAR(id), 'NULL') || ',' || NVL(TO_CHAR(amount), 'NULL'), ';')), 2) FROM order_tab WHERE ROWNUM - 字段顺序、NULL 处理、字符集(
NLS_COMP/NLS_SORT)必须完全一致,否则哈希值不同不是数据问题,而是环境差异 - 千万别在白天跑,LISTAGG 在大表上容易 OOM;也别用全表,ROWNUM 限流是底线
这个结果不是“绝对一致证明”,只是快速发现明显偏移——哈希碰撞概率极低,但无法定位哪一行错。
自动校验最易被忽略的三个点
写完脚本扔进定时任务后,90% 的失败不是代码问题,而是这三处没盯住:
-
v$archived_log视图在备库只显示已接收日志,主库查不到备库状态——定时脚本必须分主、备两套,不能复用同一段 SQL - DBMS_SCHEDULER 作业默认用 SYS 用户运行,但很多生产库禁用 SYS 执行非 DDL 操作,得显式指定
job_action的credential_name - 告警邮件发出去了,但没人看;更糟的是,脚本把错误重定向到 /dev/null,连失败日志都没留——所有输出必须落盘,哪怕只是
echo $(date) >> /u01/log/dg_check.log
定时本身很简单,难的是让每次运行都可追溯、可干预、不干扰业务。别追求“全自动”,先做到“每次失败都有明确路径可查”。


















