之前看到的一篇文章Kettle实现数据实时增量同步,这位大佬提出了 时间戳增量回滚同步的一种方式,我是根据这篇文章之上进行探索的。
但是遇到了一些问题,这里进行一下记录:
- 只能同步往前{ROLL_BACK_DAYS} day这段时间内的删除操作,因为回滚了一段时间{ROLL_BACK_DAYS} day,作者也声明了这点;
- 也只能同步往前{ROLL_BACK_DAYS} day这段时间内的删除操作,为什么呢?因为我们如果真的考虑以操作时间作为时间戳,那么在上次更新过后,即TIME_STAMP这个时间之后,源表里更新了某条数据,这条数据原来的时间戳在TIME_STAMP-{ROLL_BACK_DAYS} day 之前,那么从源表里的这条记录同时也将自己的时间戳send_time更新为当前时间,那么对比记录这步之后,这条记录就归为了new,即成为了多出来的数据,而这条数据在目标表里是有记录的,但是new跟着的操作时间上是表输出,那么就会造成主键重复但是却执行了插入这条数据的操作,虽然在作者的这个例子里面没有错误,但是我认为他其实是进行了替换,mysql是这样,但是Oracle估计就不一定会正确。而且对于主键重复插入这点,不同数据库不同的设置会有不同的结果,但是一般情况下这是不该发生的事情,会报错而导致job停止。
作者提出的这些其实本来在他回滚的时间段内是没有错误的,可能也是其业务需求刚好可以满足,但是对于我们自己需求,可能就无法满足。
而如果去掉了回滚这一步,对比记录的结果flagid就只有new,而不会有changed和deleted这两种结果。所以两表抽取数据进行比对似乎就失去了意义,与直接从源表数据进行时间戳的截取,而后面直接对目标表后面接“插入更新”似乎没有多大的区别,甚至效率更低。
对于2,这一点我觉得只有用“插入更新”是最安全的,但是作者也提出说,“插入更新”会比较慢。所以对于这一点我也没有进行过验证,只是提出这样的想法。这里做一下记录。
补充内容:关于数据抽取和同步。
在一些复杂的场景下,使用kettle进行同步。两个表的结构可能是完全不一致的,甚至某些字段根本没有,比如我们为了同步目标表,需要对源数据库里的表进行多表关联,数据格式转换decode,date_form等等,但是源表里的业务表的主键甚至和目标表的主键是不一致的,这种情况下,若同步所有字段则自己生产的目标表的主键有可能和别人真实目标表里的主键冲突,若目标表的主键是自动生成的UUID等,则可以在获取比对数据之前就过滤掉目标表的主键让其自动生产。同时需要考虑查询的组合字段同可以确定来源数据和目标表的一行数据,即至少同时可以成为两表的主键。
当然理解业务场景是是最主要的。
在实际使用的时候,发现了一些问题,在大量数据时,发现同步结果总是不对,然后想要使用全量更新时又报"违反唯一约束性条件"的错误,然后用预览的方式发现在"合并记录"步骤出现了问题,其中一条数据明明两个表都有一模一样的数据却显示的是new,在网上搜索合并记录相关的内容发现了这位大佬的记录Kettle合并记录 问题解决https://www.jianshu.com/p/d289a6c70be8,即数据量较大时,这个合并记录的结果可能出现在目标表和源表有相同记录的情况下,这条记录先出现一个new,再出现一个deleted,这也解释了为什么想要在进行一次全量更新时会报"违反唯一性约束条件"的错,同时这位大佬也给出了解决办法,即将目标表和源表数据都按照合并记录里的关键字进行排序,在我这里尝试之后发现可行。不知道这算不算是一个bug,可能是因为合并记录这样的操作,在数据量较大时不可能一次性进行比较,而是批量的执行比如先比较1000条,这样如果没有按照合并记录的关键字进行一个排序的话,可能就会出现这样的问题,关键在于避免,也就是让deleted先出现,new后出现,这样防止因为主键唯一约束性忽略了之后又删除最后发现数据量不对,又或者直接报错违反唯一性约束导致任务中断。而排序之后,就能确保是deleted先出现,而new是后出现的。不知道自己理解的是否正确。
:date:2021-06-18
今天发现遇到了一些问题。
同事说有部分内容需要重新同步一下,但是他执行之前只修改了源表中的时间戳字段,改为立即执行,执行的时候报了违反唯一性条件约束。
探究其原因发现,这条数据的上次同步时间是15天之前的,也就是说在目标表中时间戳还是15天之前的,所以执行的时候,如果说将源表的时间戳修改为了今天,(正常是每天晚上12点更新)然后就会导致取出的数据中,源表多出来了这一条而目标表取不到,就需要出入目标表,同时目标表这条数据已经存在了,就会出现重复插入,违反唯一性约束条件。
然后我们将{ROLL_BACK_DAYS} 改为20天,重新执行了一编就好了.
这次之所以需要重新同步的原因在于需要修改源表中的一条数据,需要同步到目标表中去。
因此考虑到为了方便,以后就将变量一直改为20天
同事提出,考虑到具体的业务是对消费者评价结果表的同步,对于评价结果为差评的数据,需要在15天内进行回访,如果回访后修改为好评则需要将差评改为好评。而差评数据量本身较少。也就是说,可能需要修改的数据有确切的标志位可以区分,而且属于少部分数据。基于此,考虑将好评和差评分开来获取,好评数据就取上次执行完之后的数据,差评数据取上次执行完时间节点再减去{ROLL_BACK_DAYS} 天之后的数据,然后二者union之后再按照ID排序。其他的步骤不变。
这样就可以尽可能的缩短同步时间,提高效率的同时也保证了实现了差评数据改为好评后也能被同步过去。
所以说结合具体业务很重要。