一、故障现象
某生产环境 Oracle GoldenGate 19c 的 Replicat 进程 REP_LIB 突然 Abend,Report 日志抛出核心错误:
ERROR OGG-01296 Error mapping from [SRC_SCHEMA].SRTCONTAINER to [TGT_SCHEMA].SRTCONTAINER.
ERROR OGG-01668 PROCESS ABENDING.
进程停止前最后一条有效警告:
WARNING OGG-01431 Aborted grouped transaction on [TGT_SCHEMA].SRTCONTAINER, Mapping error.
WARNING OGG-01151 Error mapping from [SRC_SCHEMA].SRTCONTAINER to [TGT_SCHEMA].SRTCONTAINER.
同时,discard 文件记录了决定性线索:
Key column DATAID (0) is missing from update on table [TGT_SCHEMA].SRTCONTAINER
Missing 1 key columns in update for table [TGT_SCHEMA].SRTCONTAINER.
二、环境信息
| 组件 | 版本/信息 |
|---|---|
| OGG 版本 | 19.1.0.0.4 |
| 操作系统 | Linux x86_64 |
| 源端数据库 | Oracle 19c,字符集 ZHS16GBK |
| 目标端数据库 | Oracle 19c,字符集 ZHS16GBK |
| Replicat 类型 | Classic Replicat |
三、排查过程
3.1 第一步:查看 Discard 文件
Discard 文件是第一现场。与常见的 ORA-00001(唯一冲突)或 ORA-12899(值太大)不同,这次 discard 没有任何 Oracle 错误号,而是直接指出:
Key column DATAID is missing from update
这说明 Replicat 在构建 UPDATE ... WHERE 语句时,发现定位行所需的键列 DATAID 在 trail 记录中不存在,导致无法定位目标行。
3.2 第二步:对比源端与目标端表结构
分别检查源端和目标端的 SRTCONTAINER 表:
结论:列名、列顺序、数据类型完全一致,但 NOT NULL 约束不同。
更关键的是索引差异:
源端索引:
TR_SRTCONTAINER_PK SRTCONTAINERID UNIQUE
目标端索引:
PK_SRTCONTAINER DATAID, SRTCONTAINERID UNIQUE
发现:
- 源端业务主键是单列
SRTCONTAINERID - 目标端主键是复合主键
(DATAID, SRTCONTAINERID)
3.3 第三步:检查 OGG 自动识别的 Key Columns
Replicat 启动日志明确显示:
INFO OGG-06510 Using the following key columns for target table [TGT_SCHEMA].SRTCONTAINER: DATAID, SRTCONTAINERID.
OGG 自动识别了目标端的复合主键,并将其作为该表的 Key Columns(用于在目标端定位行的列)。
3.4 第四步:检查源端补充日志
sql
SELECT SUPPLEMENTAL_LOG_DATA_PK FROM V$DATABASE;
-- 结果:NO
源端数据库未开启主键补充日志。
四、根因分析
4.1 OGG 的 Key Columns 识别机制
在 Classic Replicat 中,OGG 会按以下优先级自动确定目标表的 Key Columns:
- 目标端的主键(Primary Key)
- 目标端的唯一索引(Unique Index)
- 目标端所有 NOT NULL 列
本案例中,目标端存在复合主键 PK_SRTCONTAINER(DATAID, SRTCONTAINERID),因此 OGG 自动将 DATAID 和 SRTCONTAINERID 同时作为 Key Columns。
4.2 压缩更新与 Trail 记录内容
OGG Extract 默认使用**压缩更新(Compressed Updates)**模式。对于一条 UPDATE 语句,trail 中通常只包含:
- 被修改的列(After Image)
- Key Columns(用于在目标端定位行的列,取自源端的主键/唯一索引)
问题就出在这里:
| 端 | 主键/唯一键 | 对 OGG 的意义 |
|---|---|---|
| 源端 | TR_SRTCONTAINER_PK(SRTCONTAINERID) |
Extract 认为 Key = SRTCONTAINERID,因此 trail 中只保证携带 SRTCONTAINERID |
| 目标端 | PK_SRTCONTAINER(DATAID, SRTCONTAINERID) |
Replicat 认为 Key = DATAID + SRTCONTAINERID,构建 SQL 时需要这两个值 |
当源端执行如下 UPDATE 时:
sql
UPDATE SRTCONTAINER
SET UPDATETIME = ..., UPDATER = ..., STATUS = ...
WHERE SRTCONTAINERID = '...';
DATAID既不是被修改的列 ,也不是源端的主键/唯一索引列- 在压缩更新模式下,Extract 不会将 DATAID 写入 trail
- Replicat 收到记录后,发现需要
DATAID来构建WHERE DATAID = ? AND SRTCONTAINERID = ?,但 trail 中没有 → 报错Key column DATAID is missing
4.3 补充日志的角色
源端 SUPPLEMENTAL_LOG_DATA_PK = NO 意味着 Oracle redo 不会强制记录主键列的完整前像。虽然即使开启 PK 补充日志,由于 DATAID 并非源端主键的一部分 ,依然无法解决 DATAID 缺失的问题;但未开启补充日志确实是 OGG 部署的一个潜在风险点,它限制了 Extract 在更复杂场景下获取完整键值的能力。
4.4 根因总结图
源端 UPDATE (只改 UPDATER/STATUS/UPDATETIME)
│
▼
Extract 识别源端 Key = SRTCONTAINERID
│
▼
Trail 记录包含:修改列 + SRTCONTAINERID
│
▼
Replicat 识别目标端 Key = DATAID + SRTCONTAINERID
│
▼
构建 UPDATE ... WHERE DATAID=? AND SRTCONTAINERID=?
│
▼
Trail 中无 DATAID ────────► Key column DATAID is missing
│
▼
OGG-01296 Mapping Error
│
▼
OGG-01668 PROCESS ABENDING
一句话根因:目标端复合主键包含的 DATAID 列,在源端 UPDATE 产生的 trail 记录中缺失,导致 Replicat 无法构建完整的行定位条件。
五、解决方案
5.1 方案选择
由于源端业务上 SRTCONTAINERID 已能唯一标识一行(源端有唯一索引,且目标端验证无重复值),最简洁的方案是在 Replicat 参数中显式覆盖自动识别的 Key Columns ,强制只使用 SRTCONTAINERID 定位:
bash
MAP [SRC_SCHEMA].SRTCONTAINER, TARGET [TGT_SCHEMA].SRTCONTAINER, KEYCOLS (SRTCONTAINERID);
注意: 该参数必须放在通配符 MAP [SRC_SCHEMA].*.* 之前,否则会被通配符抢先匹配。
5.2 为什么不选其他方案?
| 方案 | 说明 | 未选原因 |
|---|---|---|
| 修改目标表结构 | 去掉 DATAID 或改为单列主键 |
涉及业务系统改造,风险极高 |
5.3 参数修改示例
bash
REPLICAT rep_lib
SETENV (ORACLE_HOME = "$ORACLE_HOME")
SETENV (ORACLE_SID = "[DB_NAME]")
SETENV (NLS_LANG = "AMERICAN_AMERICA.ZHS16GBK")
USERID [OGG_USER] password ***
ASSUMETARGETDEFS
DBOPTIONS DEFERREFCONST
DBOPTIONS SUPPRESSTRIGGERS
DISCARDFILE ./dirrpt/rep_lib.dsc, APPEND, MEGABYTES 1000
REPERROR (DEFAULT, ABEND)
DDL INCLUDE MAPPED, OBJTYPE 'TABLE' &
INCLUDE MAPPED OBJTYPE 'INDEX'
GROUPTRANSOPS 1000
-- 显式指定 Key Columns(必须放在通配符之前)
MAP [SRC_SCHEMA].SRTCONTAINER, TARGET [TGT_SCHEMA].SRTCONTAINER, KEYCOLS (SRTCONTAINERID);
-- 通配符映射
MAP [SRC_SCHEMA].*.*, TARGET [TGT_SCHEMA].*.*;
...
修改后重启:
bash
GGSCI> stop rep_lib
GGSCI> start rep_lib
六、经验总结与最佳实践
6.1 源端与目标端主键不一致是常见陷阱
在异构同步或数仓场景中,目标端常会增加代理键、分区键或数据仓库键,形成与源端不同的主键结构。OGG 默认按目标端约束识别 Key Columns,一旦目标端主键列在源端 trail 中无法获取,就会触发本案例的故障。
建议: 在 OGG 投产前,梳理所有同步表的源端/目标端主键差异,对不一致的表提前配置 KEYCOLS 或 FETCHCOLS。
6.2 补充日志是 OGG 的基石
虽然本次故障的直接原因不是补充日志,但 SUPPLEMENTAL_LOG_DATA_PK = NO 是一个显著风险。建议源端开启:
sql
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
这能确保 Extract 在绝大多数场景下获取到完整的主键值。
6.3 Discard 文件是排障的第一现场
遇到 Mapping Error 时,不要只看 Report 日志的 OGG-01296,一定要第一时间查看 discard 文件 。discard 中的 Key column XXX is missing 直接指明了缺失的列,能大幅缩短排障路径。
6.4 KEYCOLS 的适用边界
使用 KEYCOLS 强制指定定位列时,必须确保该列在业务上真正唯一。修改前应在目标端验证:
sql
SELECT SRTCONTAINERID, COUNT(*)
FROM [TGT_SCHEMA].SRTCONTAINER
GROUP BY SRTCONTAINERID
HAVING COUNT(*) > 1;
返回 no rows selected 方可安全使用。
关键词: Oracle GoldenGate, Replicat Abend, OGG-01296, Key Column Missing, COMPRESSUPDATES, Supplemental Log, KEYCOLS, Mapping Error