goldengate 学习系列8–当主键遇上keycols

本站文章除注明转载外,均为本站原创: 转载自love wife & love life —Roger 的Oracle技术博客

本文链接地址: goldengate 学习系列8–当主键遇上keycols

—源端主库
说明:
源端数据库:  11.2.0.4   ogg版本12.1.2

目标端数据库:10.2.0.5   ogg版本11.2.1.0.1

SQL> create table s1 (a number primary key, b number, c char(32));

Table created.

SQL> create table s3 (a number, b number);

Table created.

SQL> insert into s1 values (1,1,1);

1 row created.

SQL> insert into s3 values(1,1);

1 row created.

SQL> commit;

Commit complete.
SQL> select a,b,c,rowid from s1;

         A          B C                                ROWID
---------- ---------- -------------------------------- ------------------
         1          1 1                                AAAVViAAEAAAAC1AAA

SQL> select a,b,rowid from s3;

         A          B ROWID
---------- ---------- ------------------
         1          1 AAAVVjAAEAAAADFAAA

—目标端数据库

www.killdb.com>create table s1 (a number primary key, b number, c char(32));

Table created.

www.killdb.com>create table s3 (a number, b number);

Table created.

www.killdb.com>select * from s1;

         A          B C
---------- ---------- --------------------------------
         1          1 1

www.killdb.com>select * from s3;

         A          B
---------- ----------
         1          1

www.killdb.com>insert into s1 values (2,1,1);

1 row created.

www.killdb.com>insert into s3 values(2,1);

1 row created.

www.killdb.com>commit;

Commit complete.

www.killdb.com>select a,b,c,rowid from s1;

         A          B C                                ROWID
---------- ---------- -------------------------------- ------------------
         1          1 1                                AAAObvAAEAAAADkAAA
         2          1 1                                AAAObvAAEAAAADlAAA

www.killdb.com>select a,b,rowid from s3;

         A          B ROWID
---------- ---------- ------------------
         1          1 AAAObwAAEAAAAD0AAA
         2          1 AAAObwAAEAAAAD1AAA

—-源端进行delete操作

SQL> delete from s1;

1 row deleted.

SQL> commit;

Commit complete.

SQL> delete from s3;

1 row deleted.

SQL> commit;

Commit complete.

—目标端查询数据

www.killdb.com> select * from s1;

         A          B C
---------- ---------- --------------------------------
         1          1 1
         2          1 1

www.killdb.com>select * from s3;

         A          B
---------- ----------
         2          1

我们可以看到,这里Oracle 默认情况下,并没有对s1表进行删除操作? 为什么?
通过logminer分析源端redo

SQL> execute dbms_logmnr.add_logfile(options =>dbms_logmnr.new,logfilename =>'/home/oracle/oradata/roger/redo02.log');

PL/SQL procedure successfully completed.

SQL> EXEC SYS.DBMS_LOGMNR.START_LOGMNR(OPTIONS => SYS.DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);

PL/SQL procedure successfully completed.

SQL> col sql_redo for a80
SQL> select TIMESTAMP ,sql_redo FROM v$logmnr_contents WHERE sql_redo like '%S1%';

TIMESTAMP    SQL_REDO
------------ --------------------------------------------------------------------------------
09-JUN-15    insert into "ROGER"."S1"("A","B","C") values ('1','1','1');
09-JUN-15    delete from "ROGER"."S1" where "A" = '1' and "B" = '1' and "C" = '1
                               ' and ROWID = 'AAAVViAAEAAAAC1AAA';

SQL> select TIMESTAMP ,sql_redo FROM v$logmnr_contents WHERE sql_redo like '%S3%';

TIMESTAMP    SQL_REDO
------------ --------------------------------------------------------------------------------
09-JUN-15    insert into "ROGER"."S3"("A","B") values ('1','1');
09-JUN-15    delete from "ROGER"."S3" where "A" = '1' and "B" = '1' and ROWID = 'AAAVVjAAEAAA
             ADFAAA';

通过logminer分析目标端redo

www.killdb.com>execute dbms_logmnr.add_logfile(options =>dbms_logmnr.new,logfilename =>'/home/ora10g/oradata/roger/redo03.log');

PL/SQL procedure successfully completed.

www.killdb.com>EXEC SYS.DBMS_LOGMNR.START_LOGMNR(OPTIONS => SYS.DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);

PL/SQL procedure successfully completed.

www.killdb.com>set lines 120
www.killdb.com>col sql_redo for a90
www.killdb.com>select TIMESTAMP ,sql_redo FROM v$logmnr_contents WHERE sql_redo like '%S1%';

TIMESTAMP  SQL_REDO
---------- -----------------------------------------------------------
10-JUN-15  insert into "ROGER"."S1"("A","B","C") values ('1','1','1');
10-JUN-15  insert into "ROGER"."S1"("A","B","C") values ('2','1','1');

www.killdb.com>select TIMESTAMP ,sql_redo FROM v$logmnr_contents WHERE sql_redo like '%S3%';    

TIMESTAMP  SQL_REDO
---------- ---------------------------------------------------------------------------------------
10-JUN-15  insert into "ROGER"."S3"("A","B") values ('1','1');
10-JUN-15  insert into "ROGER"."S3"("A","B") values ('2','1');
10-JUN-15  delete from "ROGER"."S3" where "A" = '1' and "B" = '1' and ROWID = 'AAAObwAAEAAAAD0AAA';

既然源端数据库redo已经记录了相关DML的操作,那么ogg是否抓取了呢?

通过logdump分析源端trail文件

Logdump 1 >open ./dirdat/ex000004
Current LogTrail is /opt/oracle/ggs/12.1.2.1/dirdat/ex000004
Logdump 2 >ghdr on
Logdump 3 >detail on
Logdump 4 >detail data
Logdump 5 >usertoken on
Logdump 6 >FILTER include filename ROGER.S1;
Logdump 7 >next
......
Logdump 21 >n
___________________________________________________________________
Hdr-Ind    :     E  (x45)     Partition  :     .  (x04)
UndoFlag   :     .  (x00)     BeforeAfter:     A  (x41)
RecLength  :    56  (x0038)   IO Time    : 2015/06/09 22:22:22.000.000
IOType     :     5  (x05)     OrigNode   :   255  (xff)
TransInd   :     .  (x00)     FormatType :     R  (x52)
SyskeyLen  :     0  (x00)     Incomplete :     .  (x00)
AuditRBA   :         32       AuditPos   : 22032
Continued  :     N  (x00)     RecCount   :     1  (x01) 

2015/06/09 22:22:22.000.000 Insert               Len    56 RBA 5095
Name: ROGER.S1
After  Image:                                             Partition 4   G  b
 0000 0005 0000 0001 3100 0100 0500 0000 0131 0002 | ........1........1..
 0022 0000 3120 2020 2020 2020 2020 2020 2020 2020 | ."..1
 2020 2020 2020 2020 2020 2020 2020 2020           |
Column     0 (x0000), Len     5 (x0005)
 0000 0001 31                                      | ....1
Column     1 (x0001), Len     5 (x0005)
 0000 0001 31                                      | ....1
Column     2 (x0002), Len    34 (x0022)
 0000 3120 2020 2020 2020 2020 2020 2020 2020 2020 | ..1
 2020 2020 2020 2020 2020 2020 2020                |                 

Filtering suppressed      1 records
Logdump 22 >n
___________________________________________________________________
Hdr-Ind    :     E  (x45)     Partition  :     .  (x04)
UndoFlag   :     .  (x00)     BeforeAfter:     B  (x42)
RecLength  :     9  (x0009)   IO Time    : 2015/06/09 22:27:18.000.000
IOType     :     3  (x03)     OrigNode   :   255  (xff)
TransInd   :     .  (x03)     FormatType :     R  (x52)
SyskeyLen  :     0  (x00)     Incomplete :     .  (x00)
AuditRBA   :         32       AuditPos   : 178704
Continued  :     N  (x00)     RecCount   :     1  (x01) 

2015/06/09 22:27:18.000.000 Delete               Len     9 RBA 5366
Name: ROGER.S1
Before Image:                                             Partition 4   G  s
 0000 0005 0000 0001 31                            | ........1
Column     0 (x0000), Len     5 (x0005)
 0000 0001 31                                      | ....1

从trial文件的dump信息来看,确实是抽取了delete操作. 其中IOType 3表示delete,IOType 5表示insert.表明我们对S1表进行的insert 和delete操作都是被抓取了的。到这里来看,貌似一切都是正常的,但是为什么会出现s1 表数据不同步的情况呢?

对应ogg如果存在异常,那么我们可以查看相关进程的discard文件,内容如下:

Operation failed at seqno 7 rba 1907
Discarding record on action DISCARD on error 0
Problem replicating ROGER.S1 to ROGER.S1
Mapping problem with delete record (target format)...
*
A = 1
*

很明显,goldengate这里在对s1表进行delete操作的时候,map失败了。因此实际上在目标端针对s1表的delete操作根本就没有执行.

GGSCI (killdb.com) 2> view param rep1124
replicat rep1124
userid  ggs@roger,password ggs
reperror default, discard
DISCARDROLLOVER AT 20:30
discardfile ./dirrpt/rep1124.dsc, append, megabytes 50
handlecollisions
assumetargetdefs
allownoopupdates
numfiles 3000
map roger.t_ogg, target roger.t_ogg;
map roger.s1, target roger.s1, keycols (b);
map roger.s3, target roger.s3, keycols (b);
GGSCI (killdb.com) 3> stop rep1124  

Sending STOP request to REPLICAT REP1124 ...
Request processed.
GGSCI (killdb.com) 4> edit param rep1124
GGSCI (killdb.com) 5> view param rep1124

replicat rep1124
userid  ggs@roger,password ggs
reperror default, discard
DISCARDROLLOVER AT 20:30
discardfile ./dirrpt/rep1124.dsc, append, megabytes 50
handlecollisions
assumetargetdefs
allownoopupdates
numfiles 3000
map roger.t_ogg, target roger.t_ogg;
map roger.s1, target roger.s1;
map roger.s3, target roger.s3, keycols (b);

----modify rba
GGSCI (killdb.com) 6> alter rep rep1124,extrba 1907
REPLICAT altered.

GGSCI (killdb.com) 7> start rep1124

Sending START request to MANAGER ...
REPLICAT REP1124 starting

—再次check

www.killdb.com>select a,b,c,rowid from s1;

         A          B C                                ROWID
---------- ---------- -------------------------------- ------------------
         2          1 1                                AAAObvAAEAAAADlAAA

www.killdb.com>select TIMESTAMP ,sql_redo FROM v$logmnr_contents WHERE sql_redo like '%S1%';

TIMESTAMP    SQL_REDO
------------ ----------------------------------------------------------------------
10-JUN-15    insert into "ROGER"."S1"("A","B","C") values ('1','1','1');
10-JUN-15    insert into "ROGER"."S1"("A","B","C") values ('2','1','1');
10-JUN-15    delete from "ROGER"."S1" where "A" = '1' and "B" = '1' and "C" = '1
                     ' and ROWID = 'AAAObvAAEAAAADkAAA';

这里严格上来讲是keycols参数配置不当导致。 该参数的含义是指制定一个可以表示数据唯一性的列,这样以便于goldengate可以完成同步,例如delete和update.
之前之所以不能同步,报错的原因是因为目标端的s1表 b=1的结果有2条,而原端删除的是一条,很明显是无法进行map的.
下面我们将replicat进程的keycols列修改为a,进行测试发现ok,测试过程如下:

—-原端

SQL> insert into s1 values (1,1,1);

1 row created.

SQL> insert into s3 values(1,1);

1 row created.

SQL> commit;

Commit complete.

SQL> delete from s1;     

1 row deleted.

SQL> commit;

Commit complete.

—修改目标端replicat配置

GGSCI (killdb.com) 7> view param rep1124

replicat rep1124
userid  ggs@roger,password ggs
reperror default, discard
DISCARDROLLOVER AT 20:30
discardfile ./dirrpt/rep1124.dsc, append, megabytes 50
handlecollisions
assumetargetdefs
allownoopupdates
numfiles 3000
map roger.t_ogg, target roger.t_ogg;
map roger.s1, target roger.s1, keycols (a);
map roger.s3, target roger.s3, keycols (b);

—目标端

www.killdb.com>truncate table s1;

Table truncated.

www.killdb.com>insert into s1 values(3,1,1); 

1 row created.

www.killdb.com>commit;

Commit complete.

www.killdb.com>select * from s1;

         A          B C
---------- ---------- --------------------------------
         1          1 1
         3          1 1

www.killdb.com>
www.killdb.com>
www.killdb.com>select * from s1;

         A          B C
---------- ---------- --------------------------------
         3          1 1

可以看到,当调整keycols的列之后,一切正常,这是因为目标端s1表的a列的数据本身就是唯一的,因为目前只有2条数据,数值为1,3.  对应不存在主键或unique index的情况之下,如果进行update会导致目标端可能产生重复数据吗?很多人都说ogg 11.2版本不存在这个问题。包括原厂的工程师。稍后将进行相关测试!

Related posts:

  1. goldengate 学习系列1–10gasm to 11gR2 asm 单向复制(DDL支持)
  2. goldengate 学习系列2–相关配置说明
  3. goldengate 学习系列3–一对多的复制配置
  4. Goldengate monitor v11.1 Install for LinuxX86
  5. Goldengate monitor v11.1 Configure for Linux X86
此条目发表在 GoldenGate 分类目录。将固定链接加入收藏夹。

评论功能已关闭。