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

news2024/11/25 14:57:38

一、问题概述

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数据库里存储的编码格式

select dump(sms_content,1016) code,sms_content from  tab_xxx where mo_id=‘123123123132312’

CODE						   SMS_CONTENT
-------------------------------------------------- ----------------------------------------------------------------------------------------------------
Typ=1 Len=64 CharacterSet=ZHS16GBK: 78,20,20,20,20 x             :(;                    "“           ¥    ”€“"
,20,20,20,20,20,20,20,20,20,3a,28,a3,bb,20,20,20,2
0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
22,a1,b0,20,20,20,20,20,20,20,20,20,20,20,a3,a4,20
,20,20,20,a1,b1,80,a1,b0,22

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

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

Pasted Graphic 4.png

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

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

postgres=# select convert_from(decode('e59089e69e97','hex')::bytea,'utf-8');
 convert_from 
--------------
 吉林
(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后,定位有问题数据的位置后,再重新做一次自动处理的迁移)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1179448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一键搞定!多个模型结果快速合并成一个三线表,model1、model2、model3。。。

欢迎参加郑老师2023年孟德尔随机化课程即将开始 发表文章后退款!郑老师科研统计课程详情 在观察性研究中,我们经常同时构建多个统计模型,不同的模型放入不同的协变量,从零个的单因素回归分析,到多个协变量的回归模型。…

jenkins结合k8s部署动态slave

1、完成k8s连接 在完成jenkins的部署后现安装kubernets的插件 如果jenkins 是部署在k8s集群中只需要填写一下 如果是非本集群的部署则需要填写证书等 cat ./config echo ‘certificate-authority-data-value’ | base64 -d > ./ca.crt echo ‘client-certificate-data’ |…

MySQL 排序,分组,Limit的优化策略

目录 1. MySQL 中的两种排序方式 2. 排序优化策略 2.1 对排序字段添加索引 2.2 可以和WHERT字段创建联合索引 2.3 优化 FilerSort 排序方式 3. 分组优化策略 3.1 能WHERE不HAVING 3.2 减少ORDER BY,GROUP BY,DISTINCT 3.3 遵照最左前缀法则 4.…

python 之 正则表达式模块re

文章目录 findall例子:特点和注意事项: match示例:match 对象的方法和属性:注意事项: search示例:match 对象的方法和属性:注意事项: split示例:参数说明:注意…

民宿酒店服务预约小程序的作用

民宿往往是旅游者们前往某个城市感受风情常住的地方,也因此在景区或特定地方,总是不乏大小民宿品牌,但除了市场高需求外,商家们所遇的痛点也不少: 1、获客引流难 民宿生意虽然需求量高,但各家品牌众多&am…

Unity meta的一些常见属性

Unity会项目文件夹中的每个文件分配一个同名后缀为.meta的文件。 我们可以将meta文件理解不同文件之间的桥梁,通过它引擎可以管理不同文件之间的依赖关系。 使用TXT文本文件打开之后,大致属性如下: 其中常用的属性有guid、 assetBundleName以…

大模型应用于数字人

大模型会改变整个软件行业, 其中具有代表性的产品之一是数字人, 那么,什么是数字人呢?数字人涉及了哪些关键技术呢?大模型对数字人的发展带来哪些影响呢? 1. 什么数字人? 数字人目前还缺乏一个相…

【图像分类】【深度学习】【Pytorch版本】AlexNet模型算法详解

【图像分类】【深度学习】【Pytorch版本】AlexNet模型算法详解 文章目录 【图像分类】【深度学习】【Pytorch版本】AlexNet模型算法详解前言AlexNet讲解卷积层的作用卷积过程特征图的大小计算公式Dropout的作用AlexNet模型结构 AlexNet Pytorch代码完整代码总结 前言 AlexNet是…

2.数制与编码

目录 一. 进位计数制 (1)二进制,八进制,十进制,十六进制 (2)二进制,八进制,十六进制的转换 (3)十进制转换成任意进制 (4&#xf…

linux命令screen解决client_loop: send disconnect: Broken pipe

一、SSH连接服务器,client_loop: send disconnect: Broken pipe 最近需要在服务器上运行一个需要跑很久的脚本,但ssh连接的远程服务器的命令窗口经常会报:client_loop: send disconnect: Broken pipe,这个错误是ssh 命令之后没有活…

电路布线问题动态规划详解(做题思路)

对于电路布线问题,想必学过动态规划的大家都很清除。今天就来讲解一下这个动态规划经典题目。 目录 问题描述输入分析最优子结构代码 问题描述 在一块电路板的上、下2端分别有n个接线柱。根据电路设计,要求用导 线(i,π(i))将上端接线柱与下端接线柱相…

家用电脑做服务器,本地服务器搭建,公网IP申请,路由器改桥接模式,拨号上网

先浇一盆冷水! 我不知道其他运营商是什么情况。联通的运营商公网IP端口 80、8080、443 都会被屏蔽掉,想要开放必须企业备案(个人不行)才可以。也就是说,只能通过其他端口进行showtime了。 需要哪些东西? 申…

【鸿蒙软件开发】ArkUI容器组件之Grid(网格布局)

文章目录 前言一、Grid1.1 子组件GridItem是什么子组件接口属性事件示例代码 1.2 接口参数 1.3 属性1.4 Grid的几种布局模式1.5 GridDirection枚举说明1.6事件ItemDragInfo对象说明 1.7 示例代码 总结 前言 Grid容器组件:网格容器,由“行”和“列”分割…

php对字符串中的特殊符号进行过滤的方法

1、使用htmlspecialchars函数&#xff1a;此函数将特殊字符转换为对应的HTML实体。示例代码如下&#xff1a; $str "<script>alert(XSS)</script>"; $filtered_str htmlspecialchars($str); echo $filtered_str; 输出&#xff1a; <script>ale…

四阶龙格库塔与元胞自动机

龙格库塔法参考&#xff1a; 【精选】四阶龙格库塔算法及matlab代码_四阶龙格库塔法matlab_漫道长歌行的博客-CSDN博客 龙格库塔算法 Runge Kutta Method及其Matlab代码_龙格库塔法matlab_Lzh_023016的博客-CSDN博客 元胞自动机参考&#xff1a; 元胞自动机&#xff1a;森林…

线性表(顺序表,单链表,双链表,循环链表,静态链表)

目录 1.线性表的定义1.几个重要的概念2.逻辑结构 2.线性表的基本操作3.顺序表&#xff08;线性表的顺序存储&#xff09;1.静态分配2.动态分配3.顺序表的特点4.顺序表的基本操作1.插入2.删除3.查找1.按位查找2.按值查找 4.链表&#xff08;线性表的链式存储&#xff09;1.单链表…

HackTheBox-Starting Point--Tier 1---Funnel

文章目录 一 题目二 实验过程三 利用SSH隧道3.1 本地端口转发 一 题目 Tags FTP、PostgreSQL、Reconnaissance、Tunneling、Password Spraying、Port Forwarding、Anonymous/Guest Access、Clear Text Credentials译文&#xff1a;FTP、PostgreSQL、侦察、隧道技术、密码喷洒…

【笔记】判断高电平,低电平和方波的几种方法

读取某一个上拉电平信号&#xff0c;它可能输出是低电平&#xff0c;可能是高电平&#xff0c;可能是方波&#xff0c;并且这个方波不知道频率何占空比&#xff0c;那么如何来通过程序来判断呢&#xff1f;高电平和低电平都好说&#xff0c;利用HAL库读取即可&#xff0c;如下&…

在云上jupylab(codelab)常用的shell命令

1、切换当前文件目录位置&#xff1a; %cd /project/train/ 2、删除目标文件夹和文件夹下面的内容&#xff0c;注意这个r是不能少的&#xff1a; !rm -r /project/train/src_repo/dataset 3、创建数据集相关文件夹 !mkdir /project/train/src_repo/dataset 4、复制指定…

Pytorch tensor 数据类型快速转换三种方法

目录 1 通用,简单&#xff0c;CPU/GPU tensor 数据类型转换 2 tensor.type()方法 CPU tensor 数据类型转换 GPU tensor 数据类型转换 3 tensor.to() 方法,CPU/GPU tensor 数据类型转换 1 通用,简单&#xff0c; CPU/GPU tensor 数据类型转换 tensor.double()&#xff1a;…