• 【迁移ORACLE数据到MogDB/openGauss时的字符集问题】


    一、问题概述

    ORACLE数据库在存储数据的时候,有时候会存在这样一种现象,一张表里的数据,既存在UTF8字符的,也存在GBK字符的,同时还有可能存在乱码数据。

    NLS_CHARACTERSET是数据库字符集,NLS_NCHAR_CHARACTERSET是国家字符集,NLS_LANG 是 Oracle 数据库客户端的一个环境变量。

    这种问题在于ORACLE对于规定了一种字符集后,对于插入的数据并没有强校验(garbage-in–garbage-out)。但是对于PG系的数据库,数据库的字符集在最开始创建数据库的时候就指定了,而且一般情况下其中的表数据受字符集的严格校验(SQL_ASCII除外)。

    这也就导致了,原本是什么类型的字符正常可以导入到对应的字符集的库里,而原本直接存入ORACLE库里的和表原本的字符集不匹配的其他类型的字符可能无法转换,此外乱码数据可能直接不能转换到PG系的库里。(ORACLE数据库可以存储乱码数据,PG系数据库有严格校验)

    一些常见场景如下:

    1)如果恰巧数据库的字符集也是UTF8, 那么Oracle就不作任何转换直接插入到数据中.

    2)如果指定NLS_LANG是utf8, 但是输入的却是zhs16gbk的编码, 那么Oracle也会不作任何转换, 将ZHS16GBK的字符编码直接存入数据库

    3)如果数据库的字符是AL32UTF8, 您指定NLS_LANG为ZHS16GBK, 但是, 您真正输入的是UTF8的字符, 那么,Oracle会把您输入的UTF8字符当作ZHS16GBK字符转换为UTF8存入数据库. 这种情况会出现乱码。

    4)工具(putty/securecrt等等各种SSH客户端等等)设置的字符集可能导致乱码或者编码转换,客户端字符集 NLS_LANG 和 个人工具显示的字符集应该一致。

    二、问题处理方案

    1、使用SQL_ASCII字符集的数据库

    如果不考虑中文显示以及乱码显示,可以直接在目标端建一个SQL_ASCII字符集的数据库,那么所有的数据均可以导入到新的PG系的数据库里,这样就不会有编码转换。这个设置基本不用来声明所使用的编码,因为此声明会忽略编码。在大多数情况下,如果使用了任何非ASCII数据,那么我们不建议使用SQL_ASCII,因为openGauss/MogDB无法转换或者校验非ASCII字符。

    2.根据原库的编码,创建相同字符集编码的数据库

    ORACLE在创建数据库的时候,需要指定字符集。虽然上述的一些原因导致ORACLE在指定了一种字符集的数据库后,还可能存在其他类型的字符和乱码数据,但这明显是不符合规范的,因为抛开其他类型的数据,单单乱码数据就不能算作有效数据,而且其他类型的数据,属于违反了最初的规划,也不能算作正常的数据。

    因为不同的字符类型,对应存储的不同的字节长度是不一样的,例如一个汉字,在UTF8里存储为3位字节,而在GBK里存储为2个字节。

    比如一个“你”字,用UTF-8存储在ORACLE数据里,是占用3个字节,是“\xe4bda0”
    而用GBK存储在ORACLE数据里,是占用2个字节,是“\xc4e3”

    所以长度是不一致的,在它转换到PG系的数据库里时,如果不能分辨出对应的是哪种类型的字符的话,只根据固定的一种类型的字符集的话,会存在部分数据的编码无法转换,在使用MTK(云和恩墨的迁移工具)迁移数据的时候,可能类似于这种的报错。

    image.png

    对于这种报错,因为本身在原库写入的时候就存在问题,如果数据库层大量修正的话,会耗费很大精力,因此,建议规范处理流程,仅根据数据库的字符集迁移“正确”的数据,其余的有问题的数据,可以在迁移过程找到对应的位置,或者进一步判断出该类数据原本应该属于什么样的字符集,然后这些问题数据让应用自行修正。

    (1)查询存储的编码

    在遇到问题数据的时候,我们可以根据其他正常的列,定位到对应的数据行,使用ORACLE的dump函数,查看其在ORACLE数据库里存储的编码格式

    1. select dump(sms_content,1016) code,sms_content from tab_xxx where mo_id=123123123132312
    2. CODE SMS_CONTENT
    3. -------------------------------------------------- ----------------------------------------------------------------------------------------------------
    4. Typ=1 Len=64 CharacterSet=ZHS16GBK: 78,20,20,20,20 x :(; "“ ¥ ”€“"
    5. ,20,20,20,20,20,20,20,20,20,3a,28,a3,bb,20,20,20,2
    6. 0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
    7. 22,a1,b0,20,20,20,20,20,20,20,20,20,20,20,a3,a4,20
    8. ,20,20,20,a1,b1,80,a1,b0,22

    (2)根据函数或者工具检验出真实的字符编码

    然后可以把有问题的数据对应的编码,根据不同位数进行转换,看转换的数据是否是正常可读的数据,原本最开始查询的数据不用额外关注,因为可能受本地终端字符集的影响,可能本身存储的是正常的,例如,我查询到了问题列的数据导出的结果是如下。

    Pasted Graphic 4.png

    取出部分编码,进行转换,"\xe59089e69e97"根据GBK按照两位字节的形式进行转换,得到的是“鍚夋灄”,而根据UTF-8的类型进行转换,得到的是“吉林”。因此原本这条数据本身应该是UTF-8的字符集。

    可以使用相关函数进行转换,也可以使用相关在线工具,例如:字符 编码/解码 - 在线工具

    1. postgres=# select convert_from(decode('e59089e69e97','hex')::bytea,'utf-8');
    2. convert_from
    3. --------------
    4. 吉林
    5. (1 row)

    而本身这条数据正确显示的时候,应该为

    Pasted Graphic 3.png

    根据此类方法,以及对业务数据的了解,可以分辨出原本数据应该属于的字符集类型和非乱码的数据。

    (3)MTK迁移过程需要处理的部分

    手动使用COPY处理

    因为MTK迁移的过程可以指定每批次导入数据的条数,在导入数据存在此类字符集编码问题的时候,我们一般会带上igErrorData参数,会把有问题的整个批次的数据全部回滚,而其余数据继续入库。
    这个参数会在回滚那个问题批次数据的同时,把这个批次的数据记录到错误文件里,产生csv文件.

    需要注意的是,这个csv是MTK分的迁移批次,每个批次的数据条数是一致的,可能在这一个批次里,仅存在一条问题数据,但它会把整个批次的数据全部放到csv里。可以先自行查看csv筛出问题数据,或者定位问题数据。

    这个时候,我们关注的是这个csv里的正常数据,这个csv可以使用copy命令进行绕入。问题数据也可以暂时性先倒入,但是我们不关注因为字符集问题导致的查询乱码现象。

    后续可以使用openGauss/MogDB的copy带有的COMPATIBLE_ILLEGAL_CHARS参数,这个参数允许导入非法字符容错参数。此语法仅对COPY FROM导入有效。但是在导入这些存在问题的数据的时候,存在一个规则,即对于’\0’,容错后转换为空格,其他非法字符,容错后转换为问号。这部分数据即我们上文提到的属于原库就错误写入的,后续应该让业务修正。

    image.png

    MTK自动处理

    MTK(v2.9.4)新增的compatibleIlLegaLChars选项决定了mogdb/openGauss使用MTK迁移过程里,copy是否带COMPATIBLE_ILLEGAL_CHARS选项。

    如果开启后,则会直接进行入上述的转换方式,写入数据,当然问题数据需要业务修正。(一般建议手动先产生错误的数据的csv后,定位有问题数据的位置后,再重新做一次自动处理的迁移)

  • 相关阅读:
    设计模式之工厂方法模式
    k8s--基础--26.1--监控告警系统--prometheus--介绍
    2的幂次方(冬季每日一题 10)
    照片光晕光学特效模拟调色Boris FX Optics 2024 mac下载安装教程
    Nacos注册中心和服务消费方式(服务治理)
    java:使用Jedis操作redis
    王道数据结构【链表】部分代码实现(C语言)
    浅谈云上攻防系列——云IAM原理&风险以及最佳实践
    MySQL索引底层数据结构深入剖析
    搜维尔科技提供电影和动画的动作捕捉解决方案
  • 原文地址:https://blog.csdn.net/weixin_47308871/article/details/134257977