逻辑复制中的UPDATE语句

逻辑复制延时是让数据库复制运维中十分头痛的问题。有个朋友问老白,他发现LOGMINER出来的UPDATE语句与生产端的原语句差别比较大,比如下面的语句,原语句是:

UPDATE F_XXX_BACKUP SET TALLY_REMARK = ‘WIAO’ 

WHERE ACCT_ID = :B1

而目标端从从归档日志中解析出来sql_redo的语句变成了,源语句中的ACCT_ID条件没有了,反而多了BACKUP_ID等条件:

 update “XXPAY”.”F_XXX_BACKUP” set”TALLY_REMARK” = ‘WIAO’ where “BACKUP_ID” = ‘000000154720’and “TALLY_REMARK” = ‘WIAO’ and ROWID = ‘AAAL8YAAKAAA9y2AAe’;

为什么会出现这样的情况呢?要理解逻辑复制在源端与目标端的SQL语句的不同,需要首先理解逻辑复制是如何实现的。在源端,一条UPDATE语句可能是通过某个过滤条件进行的,修改数据的过程被以重做记录的方式写入重做日志或者其他复制日志中,对于Oracle来说,这种日志就是REDO LOG(对于MYSQL的BINLOG我们在本文的后面分析)。Oracle的重做日志记录记录的是记录数据块的物理变化,为了还原成逻辑复制的SQL语句,需要通过一个唯一性的主键来实现。如果某一张表没有唯一性主键,那么就需要使用额外的日志数据。这个记录就是而在逻辑复制环境下,不同数据库的ROWID是不同的,因此ROWID不能作为复制的唯一性约束条件。在这种情况下,如果UPDATE的表上面有PK,那么就会通过PK来复制数据。对于没有PK的环境,可以通过SUPPLEMENTAL LOGING指定的信息来实现唯一性约束。从表定义来看:

逻辑复制中的UPDATE语句

在表中ACCT_ID并不是唯一性的键值,因此

UPDATE F_XXX_BACKUP SET TALLY_REMARK = ‘WIAO’

WHERE ACCT_ID = :B1

这条语句可能修改1条或者多条数据库记录。而在REDO中记录的并不是SQL语句,而是在某条数据上的变更矢量。因此一条UPDATE语句,可能对应LOGMINER出来的多条记录。每条记录中包含的信息包括表名、SET列表中的OLD和NEW值,以及作为SUPPLEMENTAL LOG的的BACKUP_ID。在LOGMINER复原REDO语句的时候就会变成:

 update “SFPAY”.”F_XXX_BACKUP” set “TALLY_REMARK”= ‘WIAO’ where “BACKUP_ID” = ‘000000154720’ and “TALLY_REMARK” = ‘WIAO’ and ROWID = ‘AAAL8YAAKAAA9y2AAe’;

对于这种模式的复制,如果源端我们有一条UPDATE语句,修改了100万条记录,那么在目标端,就会被还原成100万条UPDATE语句,每条语句只修改1条记录,这样,会对复制造成一定的性能问题,造成复制延时加大。


 最后我们来看看mysql的binlog复制与Oracle的基于redo log的逻辑复制有什么异同。Mysql是通过binlog机制实现数据复制的,早期的mysql通过记录DML的SQL语句在binlog中来实现远程复制。在这种情况下,binlog中记录的不是数据块的变化矢量,而是sql语句本身,因此在源端和目标端的SQL语句是差不多的。为了确保目标端和源端的SQL语句产生的作用是相同的,BINLOG中还会记录一些上下文的信息。不过这种statement模式的binlog,有时候会出现问题,导致复制后数据不一致,因此对于一些应用场景有限制。5.1.5后,mysql开始使用了一种新的raw格式的binlog,raw格式的binlog和Oracle redo复制的原理类似了。在目标端需要通过数据变更矢量来还原SQL语句,此时,SQL语句在源端和目标端就会不同。这种模式就会出现类似ORACLE的批量修改的问题,因此mysql还支持一种叫MIX的模式,根据实际情况混合使用这两种记录格式,从而达到减少binlog量,提升复制性能的目的。

逻辑复制中的UPDATE语句》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:https://www.hashtobe.com/868.html