作者简介
石云华,Exadata中国用户组联合创始人,ORACLE ACE。毕业后一直从事Oracle数据库第三方运维服务工作,拥有十余年电信运营商、保险、税务、电力行业核心系统数据库运维经验。现就职于北京海天起点技术服务股份有限公司,oracle数据库专家组成员,Exadata部门负责人。个人著作有《Exadata实施运维指南》,《Oracle Exadata性能优化》
问题描述:
在某个迁移项目中,需要将HP-UX主机上的某个数据库用户中的数据通过GoldenGate在线迁移至Linux平台。初始化完成后,在目标端启动复制进程,但有一张表同步失败,信息如下所示。
WARNING OGG-06439 Oracle GoldenGate Delivery for Oracle, r_od.prm: No unique key is defined for table CONTINFO. All viable columns will be used to represent the key, but may not guarantee uniqueness. KEYCOLS may be used to define the key.
INFO OGG-06511 Oracle GoldenGate Delivery for Oracle, r_od.prm: Using following columns in default map by name: ID, OPER_TYPE, SERV_TYPE, SP_CODE, CONTENT_CODE, CONTENT_NAME, VALID_DATE, EXPIRE_DATE, TIME_STAMP.
INFO OGG-06510 Oracle GoldenGate Delivery for Oracle, r_od.prm: Using the following key columns for target table PDB.BB.CONTINFO: ID, OPER_TYPE, SERV_TYPE, SP_CODE, CONTENT_CODE, CONTENT_NAME, VALID_DATE, EXPIRE_DATE, TIME_STAMP.
WARNING OGG-01431 Oracle GoldenGate Delivery for Oracle, r_od.prm: Aborted grouped transaction on PDB.BB.CONTINFO, Mapping error.
WARNING OGG-01003 Oracle GoldenGate Delivery for Oracle, r_od.prm: Repositioning to rba 19831172 in seqno 0.
WARNING OGG-01151 Oracle GoldenGate Delivery for Oracle, r_od.prm: Error mapping from BB.CONTINFO to PDB.BB.CONTINFO.
ERROR OGG-01296 Oracle GoldenGate Delivery for Oracle, r_od.prm: Error mapping from BB.CONTINFO to PDB.BB.CONTINFO.
ERROR OGG-01668 Oracle GoldenGate Delivery for Oracle, r_od.prm: PROCESS ABENDING.
暂时屏蔽掉BB.CONTINFO这张表后,继续启动复制进程,后面一切正常,说明只有这张表存在问题。
问题分析:
下面,我们来分析为什么只有BD.RS_MIGU_CONTINFO.同步失败?
- 检查该表在源端数据库中的表级别附加日志。
SQL> select * from dba_log_group_columns where table_name='CONTINFO';
OWNER LOG_GROUP_NAME TABLE_NAME COLUMN_NAME POSITION LOGGIN
---------- --------------- -------------------- --------- ---------- ------
BB GGS_648299 CONTINFO SP_CODE 1 LOG
BB GGS_648299 CONTINFO CONTENT_CODE 2 LOG
BB GGS_648299 CONTINFO VALID_DATE 3 LOG
可见,该表存在附加日志,由(SP_CODE,CONTENT_CODE,VALID_DATE)这三列组成。这三列也是该表的主键列。
- 对比该表在源端和目标端数据库中的表结构。
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','CONTINFO','BB') FROM DUAL;
DBMS_METADATA.GET_DDL('TABLE','CONTINFO','BB')
--------------------------------------------------------------------------
CREATE TABLE "BB"."CONTINFO"
( "ID" VARCHAR2(32),
"OPER_TYPE" VARCHAR2(8),
"SERV_TYPE" VARCHAR2(8) NOT NULL ENABLE,
"SP_CODE" NUMBER(8,0) NOT NULL ENABLE,
"CONTENT_CODE" VARCHAR2(16) NOT NULL ENABLE,
"CONTENT_NAME" VARCHAR2(64),
"VALID_DATE" DATE NOT NULL ENABLE,
"EXPIRE_DATE" DATE,
"TIME_STAMP" DATE,
CONSTRAINT "PK_CONTINFO" PRIMARY KEY ("CONTENT_CODE", "SP_CODE", "VALID_DATE") DISABLE, SUPPLEMENTAL LOG GROUP "GGS_648299" ("SP_CODE", "CONTENT_CODE", "VALID_DATE") ALWAYS,
SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS,
SUPPLEMENTAL LOG DATA (UNIQUE INDEX) COLUMNS,
SUPPLEMENTAL LOG DATA (FOREIGN KEY) COLUMNS
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
TABLESPACE "TS_PD01"
SQL>
对比后,发现源端和目标端的表结构完全一致。
- 暂时还没有想明白问题出在哪,用logdump先看看源端生成的Trail文件中的内容。
oracle@ngdb01:/backup/ogg$./logdump
Oracle GoldenGate Log File Dump Utility for Oracle
Version 12.3.0.1.4 OGGCORE_12.3.0.1.0_PLATFORMS_180415.0359
Copyright (C) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
Logdump 2 >open dirdat/od000000000
Current LogTrail is /backup/ogg/dirdat/od000000000
Logdump 3 >ghdr on
Logdump 4 >detail on
Logdump 5 >detail data
Logdump 6 >reclen 200
Reclen set to 200
Logdump 7 >filter include filename BB.CONTINFO
Logdump 8 >n
___________________________________________________________________
Hdr-Ind : E (x45) Partition : . (x0c)
UndoFlag : . (x00) BeforeAfter: A (x41)
RecLength : 166 (x00a6) IO Time : 2020/08/18 16:18:36.000.000
IOType : 134 (x86) OrigNode : 255 (xff)
TransInd : . (x01) FormatType : R (x52)
SyskeyLen : 0 (x00) Incomplete : . (x00)
AuditRBA : 152746 AuditPos : 298732648
Continued : N (x00) RecCount : 1 (x01)
2020/08/18 16:18:36.000.000 GGSUnifiedUpdate Len 166 RBA 17155441
Name: BB.CONTINFO (TDR Index: 40)
After Image: Partition 12 G m
0000 0051 0003 000a 0000 0000 0000 000a a6b9 0004 | ...Q................
000d 0000 0009 3437 3937 3533 3535 3600 0600 1500 | ......479753556.....
0032 3031 392d 3031 2d30 323a 3030 3a30 303a 3030 | .2019-01-02:00:00:00
0007 0015 0000 3939 3939 2d31 322d 3331 3a30 303a | ......9999-12-31:00:
3030 3a30 3000 0300 0a00 0000 0000 0000 0aa6 b900 | 00:00...............
0400 0d00 0000 0934 3739 3735 3335 3536 0006 0015 | .......479753556....
0000 3230 3139 2d30 312d 3032 3a30 303a 3030 3a30 | ..2019-01-02:00:00:0
3000 0700 1500 0032 3032 302d 3038 2d32 303a 3030 | 0......2020-08-20:00
3a30 303a 3030 | :00:00
Before Image Len 85 (x00000055)
BeforeColumnLen 81 (x00000051)
Column 3 (x0003), Len 10 (x000a)
0000 0000 0000 000a a6b9 | ..........
Column 4 (x0004), Len 13 (x000d)
0000 0009 3437 3937 3533 3535 36 | ....479753556
Column 6 (x0006), Len 21 (x0015)
0000 3230 3139 2d30 312d 3032 3a30 303a 3030 3a30 | ..2019-01-02:00:00:0
30 | 0
Column 7 (x0007), Len 21 (x0015)
0000 3939 3939 2d31 322d 3331 3a30 303a 3030 3a30 | ..9999-12-31:00:00:0
30 | 0
After Image Len 81 (x00000051)
Column 3 (x0003), Len 10 (x000a)
0000 0000 0000 000a a6b9 | ..........
Column 4 (x0004), Len 13 (x000d)
0000 0009 3437 3937 3533 3535 36 | ....479753556
Column 6 (x0006), Len 21 (x0015)
0000 3230 3139 2d30 312d 3032 3a30 303a 3030 3a30 | ..2019-01-02:00:00:0
30 | 0
Column 7 (x0007), Len 21 (x0015)
0000 3230 3230 2d30 382d 3230 3a30 303a 3030 3a30 | ..2020-08-20:00:00:0
30 | 0
Logdump 10 >n
从Trail文件来看,当前显示的这条记录是一个update操作,在Trail文件中记录了主键列和修改列的前、后镜像值。因为该表的附加日志是主键列,所以Trail文件中的信息是正常的。
- 至此,这个问题有些疑惑了,还没有想明白怎么回事,于是重新回过头再仔细查看报错时的日志,刚才被忽略的一些信息再次进入眼前。
WARNING OGG-06439 Oracle GoldenGate Delivery for Oracle, r_od.prm: No unique key is defined for table CONTINFO. All viable columns will be used to represent the key, but may not guarantee uniqueness. KEYCOLS may be used to define the key.
当BB.CONTINFO同步失败之前,目标端的GoldenGate提示这张表上没有唯一键,于是将该表的所有列当作唯一键。
这张表有主键,所以源端的附加日志只只记录了主键列来当作唯一键,用来定位具体的列。目标端和源端的表结构完全一致,理论上,目标端也应该把这个主键列当作唯一键才对,但为什么没有这样做?
- 再一次回头查看表结构,这一次又有重大发现,原来这张表的主键当前是disable状态。
CONSTRAINT "PK_CONTINFO" PRIMARY KEY ("CONTENT_CODE", "SP_CODE", "VALID_DATE") DISABLE,
至此,整个问题已经完全想明白了。这张表有主键,但处于disable状态,HP-UX上的GoldenGate在添加表级别附加日志时,仍然只将主键列加入附加日志组中,同样,Trail文件中也只有主键列的值和修改列的值。目标端Linux上的GoldenGate在获取这张表的表结构时,发现主键是disable状态,于是只能将所有列当作唯一键列,在解析Trail文件构造SQL语句时,对于update操作,构造出来的SQL语句格式应该为:
update BB.CONTINFO set 某列 = 值 where 列1=… and 列2=… and 列3=… and 列4=… and 列5=…. and 列6=….
然而,在Trail文件中,update操作只记录了主键列的值和修改列的值。这样,就无法正常构造出SQL语句。所以报错信息只有:
ERROR OGG-01296 Oracle GoldenGate Delivery for Oracle, r_od.prm: Error mapping from BB.CONTINFO to PDB.BB.CONTINFO.
如果已经构造出SQL语句,则报错时,会将报错的SQL语句打印出来。
- 对于已经disable的主键,在HP-UX上,为什么GoldenGate还是把它当作唯一键列呢?我认为这是GoldenGate在HP-UX版本上的缺陷,这种disable的主键,是无法保证唯一性的,当然也就不能将这种主键作为表级别的附加日志。为了验证这一点,进行了如下测试,在Linux主机上对于这种主键为disable状态的表,添加表级别附加日志时,GoldenGate会将所有列当作唯一键列。
问题处理:
让业务人员确认这个主键是否置于enable,最终,针对该表重新初始化。
原创文章,版权归本文作者所有,如需转载请注明出处