异构数据库迁移过程中应该避雷的七个大坑

举报
小云悠悠zZ 发表于 2023/01/31 23:05:36 2023/01/31
【摘要】 除了空值和空字符串以外,其实还有⼀个隐藏的⼤boss——固定⻓度类型中的空格值。以Oracle DB为例,char类型⽤于存放固定⻓度的字符串,⽽⻓度不⾜的字符串则会被⾃动补充空格,对于这种值,⽆论是char_col=''还是char_col is null均⽆法识别,只能通过trim(char_col) is null识别,对此值使⽤length函数会返回本字段的⻓度,⼀个⾮0值。

一、空值和空字符串

对于Oracle DB⽽⾔,空值和空字符串是同⼀回事,其中判断某个值是否为空值/空字符串统⼀使⽤"IS NULL"即可,⾄于=''是⽆效的。

这点对于其余数据库来说,可真不⼀定了。就源端为Oracle DB,⽬标端为其余数据库的项⽬⽽⾔,我们需要与开发商确认好,⽬标端究竟⽤哪种值表⽰源端的空值/空字符。⽽对于实时同步的项⽬来说,还需要在全量同步以及增量同步期间保持数据的⼀致。

除了空值和空字符串以外,其实还有⼀个隐藏的⼤boss——固定⻓度类型中的空格值。以Oracle DB为例,char类型⽤于存放固定⻓度的字符串,⽽⻓度不⾜的字符串则会被⾃动补充空格,对于这种值,⽆论是char_col=''还是char_col is null均⽆法识别,只能通过trim(char_col) is null识别,对此值使⽤length函数会返回本字段的⻓度,⼀个⾮0值。⽽这种数据同步到adb后则表现有⼀定差异了,char_col=''可以识别这种数据(哪怕ADB中也是⽤了固定⻓度的数据类型),然⽽对这个值使⽤char_length函数,结果会返回0,如果实在要把这种数据抓出来,我们还得加⼀个条件oct_length(char_col)>0。很明显,这⼜是⼀个坑!

二、数据类型转换问题

跨数据库的表字段数据类型转换工作主要涉及“精度”、“效率”、以及“兼容性”等方面。部分数据同步软件确实具备自动转换的功能,然而这种情况,仅对于管理规范的数据库适用,不规范的库则需要耗费较大精力了,下面举几个典型的例子说明这个问题:

  • 以从Oracle DB到PG的同步为例,整型的值固然可以通过number类型(不设定精度和小数位)存放到源端Oracle数据库中,问题来了,PG中应该用啥字段对应了,仅仅安全起见,免得精度丢失,那肯定是numeric类型,然而这毫无疑问存在性能损失。Bigint等类型自然是更好的选择,可是这又牵涉到与开发商沟通这样有没有可能导致应用报错等情况了,这又是一个工作量。
  • 以从Oracle DB到DB2的同步为例,DB2有一个隐性要求,组成主键的字段值前后不能包含空格,否则会被过滤掉,这样会造成一些在源端Oracle数据库本来就不相同的两条记录的在目标端DB2库被误判为同一条记录进而引发数据冲突,影响数据同步。

不要问为什么要在id类字段加空格:第一,这是合法的;第二,这未尝不是一种有创意的备份数据方法。这么干,真的,没毛病!

  • 以从Oracle DB到ADB的同步为例,由于MPP架构需要,我们需要额外指定DISTRIBUTED列。对于ADB而言,这里还有一个附带的要求,这个列应当为主键的一部分。
  • 以Oracle DB到HBase的同步为例,HBase是强制要求有主键的,否则不能同步。之前的项目中,笔者被迫无奈拿Oracle的转换后的ROWID作为HBase的rowkey,满足其同步前置条件。

三、字符集转换问题

字符集转换深究起来其实并不是容易的事情,几年前参与的一个O2O同步(即Oracle到Oracle的同步,下同) 迁移项目中,涉及了BIG5到UTF8的转换,当时的同步工具为OGG。这个项目中各种乱七八糟的数据至今仍然对笔者历历在目,当然,这也让笔者能更有经验地处理异构数据库同步中的字符集转换问题。

跨字符集转换的工作其实陷阱不少,因此,条件允许的话,建议尽量规避。当然,遇到PG这种服务器端不支持GBK,而源端Oracle DB偏偏是GBK的情况,那只好迎难而上了,下面为笔者的建议:

  • 涉及中文的情况,所见非所得,判断一条中文记录是否正常的依据,应该为其十六进制编码是否正常。对于Oracle DB而言,我们可以用dump函数,其余DB需要找到类似的。
  • 中文为多字节字符,在不同的字符集下占用的字节数并不一致,典型例子为GBK为2字节,UTF8为3字节。目标端环境可能需要相应调整字节宽度。
  • 不同字符集所涵盖的汉字是不一样的,例如BIG5中就没有“邨”字。
  • 字符集中有一个“自定义”区域,如不进行特殊处理,有可能导致数据丢失。
  • “乱码”会造成很大的困扰,对于Oracle DB而言,大致有如下几种情况:
  • 无法通过Oracle自带convert函数转换为目标库编码,以ADB为例,这部分数据会导致GPFDIST导入失败,进而影响数据全量同步。
  • 可以通过Oracle自带convert函数转换为目标库编码,但无法重新转换为原有数据,这部分数据会有潜在的数据丢失影响,对于迁移类项目需要重点关注是否涉及“自定义”字符区域。
  • 含义不明的单字节字符,如chr(0)、chr(255),这些字符往往夹杂在正常的字符中,以ADB为例,涉及dts( Data Transmission Service, 数据传输服务,系阿里的数据同步工具/服务)增量同步的话,相应记录有数据一致性风险。

四、特殊字符处理

对于数据库异构同步而言,特殊的字符,诸如单引号、双引号、换行、斜杠、反斜杠等等也是一个困扰项,这一点在数据全量同步阶段尤其明显。

对于文本方式的全量数据同步来说,我们可以考虑下述几种方式:

  • 使用CSV格式;
  • 使用多字节分隔符;
  • 进行数据清洗;
  • 仅同步“正常”数据,“特殊”数据另行处理。

五、异常记录处理

这里的异常记录,指的是那种本身就违反数据库规范,不应该插入到数据库中的记录。

以Oracle DB为例,笔者遇到的记录有异常日期格式以及异常数值两类。

  • 异常日期格式,典型例子有"0000-00-00 00:00:00"和"2022-02-30 00:00:00"。笔者在好几个客户环境都遇过这种数据,以至于笔者觉得这很“常见”,需要加到测试项目里面。笔者这段时间做的Oracle到ADB同步项目确实遇到这种数据了,后者还造成dts的增量同步中断,风险很高。所幸笔者的dts源端库是基于OGG的目标库部署的,Oracle自己的OGG工具也不能同步这种数据,这间接地挡了这部分异常的增量数据。在此基础上,笔者只需要修复已有的异常数据即可,修复方法也很简单,先+1再-1能修复大部分数据,至于不能修复的只能和业务协商重置一个值了。
  • 异常数值类型,典型例子为NaN(即Not a Number),之前在工作环境中遇到,当时的场景为O2O同步 ,比较可怕的是连基本“来者不拒”的数据泵都无法同步这种数据。考虑到这个环境没遇过这种数据,没做相应的测试。

六、全量同步测试

通常情况下,各种数据同步软件都会自带全量数据同步的功能,至于这个功能的效率、资源消耗、空间占用等项目需要进行评估。如果其不能满足需求,则可能需要考虑替代的手段。

在选取测试表的时候,笔者考虑综合下面几个因素选择几个测试表:

  • 需要包括大表,大表往往是个瓶颈项;
  • 需要囊括本次同步涉及表的字段类型;
  • 如果环境中存在中文等多字节数据,则建议包含这种表;
  • 建议找静态的表或者准静态进行测试,以方便核对数据一致性。

七、增量同步测试

作为数据同步项目,同步效率是一个重要因素,笔者建议在搭建完整的同步链路之前,拿数据变更频繁的关键表进行测试,通过单表单进程的方式,剔除潜在的配置不当风险。

对于这方面,我建议如下:

  • 尽量使用真实的数据;

我这次测试通过Ogg同步增量数据,比较切合生产实际变更情况,这种方式可以参考。

  • 增量同步发起后,在目标数据库后台观察对应的SQL语句。以笔者本次项目为例,这个阶段发现了两个问题:
  • 由于大小写敏感问题,dts目标侧未成功识别出主键,导致所有字段被加到where条件,影响效率,此问题后来通过修改同步配置解决。
  • 我观察到dts侧虽然设置了高并发度,但实际运行中,仅个别进程工作,其余处于空闲状态,无法充分利用资源。此问题后来通过修改配置参数解决。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。