逻辑复制延时是让数据库复制运维中十分头痛的问题。有个朋友问老白,他发现LOGMINER出来的UPDATE语句与生产端的原语句差别比较大,比如下面的语句,原语句是:
UPDATE F_XXX_BACKUP SET TALLY_REMARK = 'WIAO' WHERE ACCT_ID = :B1 |
update "XXPAY"."F_XXX_BACKUP" set"TALLY_REMARK" = 'WIAO' where "BACKUP_ID" = '000000154720'and "TALLY_REMARK" = 'WIAO' and ROWID = 'AAAL8YAAKAAA9y2AAe'; |
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量,提升复制性能的目的。