Oracle-TiDB迁移-生僻字乱码问题

作者: longzhuquan 原文来源: https://tidb.net/blog/d4d52358

背景

某去O场景业务上线测试,再执行某张表缩字段时报错。

现象

执行缩字段语句

ALTER TABLE schemaname.tablename  MODIFY COLUMN licenseno varchar(50)  CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '发动机号' ;

报错信息

"incorrect string value '\xED' for column ‘licenseno’"

数据库版本

Oracle-TiDB迁移-生僻字乱码问题_第1张图片

推测原因

TiDB报错"incorrect string value '\xED' for column ‘licenseno’",一般来说此类报错出现在插入语句阶段,用户在插入与字符集集不匹配的非法字符时报错。而题主本次进行进行的缩字段语句,其原理操作步骤大致分为:将相关表数据由 KV 全部 LOAD 到 TIDB 内存中,在内存中进行修改数据,将修改完的数据进行合规性校验,检验完成后回填到 KV 中。

所以推测是在数据回填进行合法性校验时出现了错误。

查看数据库字符集

character_set_client        utf8mb4
character_set_connection        utf8mb4
character_set_database        utf8mb4
character_set_filesystem        binary
character_set_results        
character_set_server        utf8mb4
character_set_system        utf8
character_sets_dir        /usr/local/mysql-5.6.25-osx10.8-x86_64/share/charsets/

查询原表中是否含有非法字符

select _tidb_rowid, convert(a using utf8mb4) from table where convert(a using utf8mb4) != a;

经过排查发现 “licenseno” 是一个车牌号,其字段类型为 “varchar(200)”,而表中确实存在非法字符,其中此字段的值为 “F XXXXX”。

Oracle-TiDB迁移-生僻字乱码问题_第2张图片

此时怀疑是不是 TiDB 对于一些生僻词不识别或者转储有错误。于是进行人工校验

Oracle-TiDB迁移-生僻字乱码问题_第3张图片

结果插入正常, 怀疑错误

此时回想数据来源,此数据是从 ORACLE 库中,通过 sqluldr2 导出成 CSV 文件,在通过 lighting 导入到 TiDB。合理怀疑链路过程某一环节有问题。单没有方向,只能从源头开始调查。

ORACLE端

查询数据正常,但对于生僻字来说肉眼看不一定准确,固将所见字转换为16进制。

ORACLE 16进制为 Typ=1 Len=10 CharacterSet=AL32UTF8: f0,a4,be,82,46,44,37,4d,36,38

TIDB 16进制为 EDA193EDBE824644374D3638

Oracle-TiDB迁移-生僻字乱码问题_第4张图片

Oracle-TiDB迁移-生僻字乱码问题_第5张图片

明显看到两边存储码不相同。

验证结果,刚刚在 TIDB 中曾成功插入过“”字,查看手动插入的16进制,与 Oracle 相同,证明源端数据无问题。

Oracle-TiDB迁移-生僻字乱码问题_第6张图片

继续排查,sqluldr2 导出文件,建立一张测试表,仅插入所需数据,使用工具导出。然后通过VIM 命令 ":%!xxd" 查看字段16进制。明显看到此时转码已经出现问题,并不符合ORACLE存储的“ f0,a4,be,82,46,44,37,4d,36,38 ”,而是转换成了“ EDA193EDBE824644374D3638 ”。

为对比验证,现场使用kettle重新导出csv文件,以相同的方式查看“XXX”的16进制,导出转码为"F0A4 BE824644374D3638"正常转码。

Oracle-TiDB迁移-生僻字乱码问题_第7张图片

由此判断为 sqluldr2 问题,查阅相关资料得知使用sqluldr2工具导出csv文件时。对于某些生僻字转码会存在转码错误的bug,对于这类生僻字会转换成白+宛两个字的编码,但实际占有一个字符位置。从而导致存在非法字符。

另外存在疑问,导入时为何不进行数据合法性校验。咨询相关人员得到如下建议:使用lighting导入时,若原csv文件为utf8或binary编码,则lighting导入时不进行任何设置。导入模式为 kv 时的方法,不存在问题。若导入时csv文件为其他编码格式,且未使用 data-character-set 参数时,则 lighting 会默认 csv 文件是二进制编码且直接使用 utf8 格式,此时转码可能会存在未知问题。

结语

使用三方工具还是存在一些风险,不过目前此方案确实迁移速度较快(相比较于 KTL 工具)。另外听PingCap 正在推出自己的异构迁移工具,我司也正在进行内部测试,总体来说其速度相对于 kettle 还是比较快,但仍赶不上 sqluldr2 导出 lighting 的速度,且目前还存在一些问题,待我方测试完成后,各位如有兴趣,我会献上测评。

你可能感兴趣的:(oracle,tidb,数据库)