goldengate同步无主键无唯一索引表的问题以及解决方案--更新关于附加日志

2020-08-05 15:26:51 浏览数 (2)

一【环境描述】

1、goldengate版本

./ggsci -v

Oracle GoldenGate Command Interpreter for Oracle

Version 11.2.1.0.4_02 15864821 OGGCORE_11.2.1.0.5_PLATFORMS_121214.0600_FBO

Linux, x64, 64bit (optimized), Oracle 11g on Dec 14 2012 11:41:04

2、database版本

sqlplus -v

SQL*Plus: Release 11.2.0.3.0 Production

3、表结构

备注:表无任何索引和约束,sxiaoxu表示源表,txiaoxu表示目标表.

代码语言:javascript复制
create table sxiaoxu
(
  id               int not null,
  name         varchar2(50),
  age            int not null,
  sex             char(1)
)
create table txiaoxu
(
  id               int not null,
  name         varchar2(50),
  age            int not null,
  sex             char(1)
)

4、测试场景

4.1 构建完全相同数据,更新全部数据以及随机更新数据,查看目标端更新情况

4.2构造keycols相同的整条记录不相同,更新全部数据以及随机更新数据,查看目标端更新情况

4.3当表结构发生变化时,验证同步存在问题

4.4当表结构存在大字段类型时,更新数据,查看目标端更新情况

二【测试过程针对构建完全相同以及keycols相同的记录不同】

备注--构建完全相同数据,更新全部数据以及随机更新数据,查看目标端更新情况

--准备工作完成包括配置抽取进程,应用进程以及数据库级别附加日志、表附加日志

1、验证表附加日志是所有列

代码语言:javascript复制
info trandata XIAOXU.SXIAOXU
Logging of supplemental redo log data is enabled for table XIAOXU.SXIAOXU.
Columns supplementally logged for table XIAOXU.SXIAOXU: AGE, SEX, ID, NAME.

2、构建5条完全一样数据

代码语言:javascript复制
insert into xiaoxu.sxiaoxu values(1,'xiaoxu',18,'m');
insert into xiaoxu.sxiaoxu values(1,'xiaoxu',18,'m');
insert into xiaoxu.sxiaoxu values(1,'xiaoxu',18,'m');
insert into xiaoxu.sxiaoxu values(1,'xiaoxu',18,'m');
insert into xiaoxu.sxiaoxu values(1,'xiaoxu',18,'m');

3、验证同步情况

3.1针对插入完全没有问题

--extract抽取情况

代码语言:javascript复制
GGSCI 1> stats txiaoxu
Sending STATS request to EXTRACT TXIAOXU ...
Start of Statistics at 2019-04-03 21:17:22.
Output to ./dirdat/xu:
Extracting from XIAOXU.SXIAOXU to XIAOXU.SXIAOXU:
*** Total statistics since 2019-04-03 21:16:00 ***
 Total inserts                                      5.00
 Total updates                               0.00
 Total deletes                               0.00
 Total discards                              0.00
 Total operations                            5.00
--replicat进程

GGSCI> stats rxiaoxu
Sending STATS request to REPLICAT RXIAOXU ...
Start of Statistics at 2019-04-03 21:18:43.
Replicating from XIAOXU.SXIAOXU to XIAOXU.TXIAOXU:
*** Total statistics since 2019-04-03 21:17:11 ***
 Total inserts                               5.00
 Total updates                               0.00
 Total deletes                               0.00
 Total discards                              0.00
 Total operations                            5.00

3.2 一次性更新全部5条数据,目标同样没有问题

代码语言:javascript复制
update xiaoxu.sxiaoxu set name='xuxiao';

--检查源和目标数据完全一致的.对于源端5条更新,在目标更新都加上rownum=1来保证每次都更新一条.对logdump中类型是GGSPKUpdate.

通过打印SQL,目标端执行如下更新,set和where都加上所有列且where后面加上rownum=1来保证每次更新都是一条.

代码语言:javascript复制
UPDATE "XIAOXU"."TXIAOXU" SET "ID" = '1',"NAME" = 'xuxiao',"AGE" = '18',"SEX" = 'm' WHERE "ID"='1' AND "NAME"='xiaoxu' AND "AGE"='18' AND "SEX"='m' AND ROWNUM = 1
Statement length: 164
(S)top display, (K)eep displaying (default):

3.3 源端随机更新一条,目标只能从第一条处理,只是顺序乱,但是数据是一致的.

--表数据以及rowid情况

比如把sxiaoxu中最后一条记录的name更新xiaoxu,目标其实是更新第一条.

代码语言:javascript复制
update xiaoxu.sxiaoxu set name='xiaoxu' where rowid='AADwvrAAFAACEqkAAE';
commit;

目标表txiaoxu,是更新第一条数据

3.4 如果源表表结构发生,如是大字段会造成数据不一致问题.如是非大字段,必须重新删除附加日志,再次增加,否则会造成无法捕获增加列更新情况.

备注:针对大字段是无法加入到附加日志中.所以where中无大字段列,导致缺少一个列来判断重复值,导致更新异常.

代码语言:javascript复制
alter table xiaoxu.sxiaoxu add  (addresss clob);
alter table xiaoxu.txiaoxu add  (addresss clob);

--重启抽取进程以及应用进程

--验证附加日志,发现附加日志并自动更新,需要重新删除后再增加,否则会造成extract无法捕获到新增列更新的情况.

代码语言:javascript复制
GGSCI () > info trandata xiaoxu.sxiaoxu
Logging of supplemental redo log data is enabled for table XIAOXU.SXIAOXU.
Columns supplementally logged for table XIAOXU.SXIAOXU: AGE, SEX, ID, NAME.

【验证插入数据】

--验证源端插入数据,插入数据在最后一行

--验证目标插入数据,发现插入数据变成第一行

【验证更新数据】

--源端更新数据最后一条数据

代码语言:javascript复制
update xiaoxu.sxiaoxu set addresss='newshanghai' where rowid='AADwvrAAFAACEqkAAF';
commit;

--目标检查数据--更新无异常

--源端更新数据第2条数据,name='xiaoxu'时,目标还是更新第一条数据.

代码语言:javascript复制
update xiaoxu.sxiaoxu set addresss='oldshanghai1' where rowid='AADwvrAAFAACEqkAAE';
commit;

--目标检查数据--目标还是更新第一条数据,因为addresss附加日志没有捕获到.

3.5 如果源表表结构发生,比如增加字段,对于附加日志是否需要删除重新增加由以下条件决定:

a:如果附加日志本身就是all columns的情况,那么增加或者删除列的情况,重启抽取进程即可,all columns分为2种情况,1种是超过32列时,增加附加自动all columns,2种sql命令手动指定all columns来实现(列小于32也没有问题,取消超过32列限制),11版本的ogg中ggsci窗口还没有all columns,12c的ggsci中支持. 11g只能通过sql命令alter table xiaoxu.sxiaoxu add supplemental log data(all) columns;

b:如果附加日志本身是conditional(有条件),增加或者删除列后,需要删除原来附加日志信息,再次增加新附加日志信息,然后重启抽取进程--主要是为了刷新数据字典缓存信息,如果没有更新附加日志或者没有重启抽取日志,原来有值,更新其他字段时,会造成这个字段在目标被更新成NULL,这个是不规范造成,从而造成后续数据不一致,出现常见错误1403错误.

c:如果增加、删除、修改的是大字段类型的列,例如clob,这个列无法增加附加日志中,那么则忽略附加删除删除与增加问题.但是抽取进程还是要重启来刷新数据字典缓存信息.

代码语言:javascript复制
alter table xiaoxu.sxiaoxu add ( addresss varchar2(30));
alter table xiaoxu.txiaoxu add ( addresss varchar2(30));

--插入数据

如果抽取进程不重启,则捕获到空值.

代码语言:javascript复制
INSERT INTO "XIAOXU"."TXIAOXU" ("ID","NAME","AGE","SEX","ADDRESSS") VALUES ('1','xiaojing1','18','m','')
Statement length: 106

如果抽取进程重启,则捕获到到正常值

代码语言:javascript复制
INSERT INTO "XIAOXU"."TXIAOXU" ("ID","NAME","AGE","SEX","ADDRESSS") VALUES ('1','xiaojing2','18','m','shanghai')
Statement length: 114

--验证更新(重启抽取进程,trandata是没有这个字段)

代码语言:javascript复制
update xiaoxu.sxiaoxu set name='newxiaojing3' where rowid='AADwvrAAFAACEqkAAJ';
commit;
select rowid,a.name,to_char(addresss) from xiaoxu.sxiaoxu a;
AADwvrAAFAACEqkAAJ newxiaojing3 shanghai

目标更新--发现源端地址变成空值了,因为附加日志问题导致的.如果更新地址这一列则没有问题,如果不更新地址这一列,直接变成NULL,注意这个坑

代码语言:javascript复制
UPDATE "XIAOXU"."TXIAOXU" SET "ID" = '1',"NAME" = 'newxiaojing3',"AGE" = '18',"SEX" = 'm',"ADDRESSS" = NULL WHERE "ID"='1' AND "NAME"='xiaojing3' AND "AGE"='18' AND "SEX"='m' AND "ADDRESSS" IS NULL AND ROWNUM = 1
Statement length: 214

3.6 如果使用keycols,keycols的值存在相同,但每一条记录所有字段组合是唯一的情况,如果存在2条记录,更新最后一条,如果源与目标记录顺序一致,那么更新会造成错误错误,如果记录顺序刚好相反,那么更新则没有问题.那么这个时候使用keycols是不合适的,没有达到标识唯一的记录,虽然速度会快些,还不如去掉keycols来保证数据完整性.

三【针对无主键无唯一索引的表,goldengate优化方案】

1、修改表结构,增加一个虚拟列使用sys_guid()函数来产生唯一值。这个需要考虑到表结构更改以及增加字段时间,对于新表增加影响会小,但是已存在大表,需要停机窗口来增加字段.

2、使用keycols来指定标识唯一值列(可以是多列),如果选出列无法满足,会出现如下情况

如果存在2条记录,更新最后一条,如果源与目标记录顺序一致,那么更新会造成错误错误,如果记录顺序刚好相反,那么更新则没有问题.那么这个时候使用keycols是不合适的,没有达到标识唯一的记录,虽然速度会快些,还不如去掉keycols来保证数据完整性.

3、无主键无唯一表,表结构发生变化,必须删除附加日志,再次增加附加(针对add trandata方式增加,如果是add schematrandata不存在这个问题),否则会出现数据不一致情况,主要schematrandata与trandata实现方式不同,trandata是ddl操作,对于高并发表无法获取锁,schematrandata通过调用接口实现,取消ddl加锁.后续会具体分析下.

4、针对无主键的全列附加日志,对于线上系统,尤其是oracle数据库,如果是大表全列附加日志,需要考虑数据库归档空间增加以及OGG抽取给数据库造成额外IO影响,需要评估下.

0 人点赞