写点什么

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

  • 2023-08-18
    北京
  • 本文字数:1589 字

    阅读完需:约 5 分钟

作者: 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’"
复制代码

数据库版本

推测原因

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


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


查看数据库字符集


character_set_client        utf8mb4character_set_connection        utf8mb4character_set_database        utf8mb4character_set_filesystem        binarycharacter_set_results        character_set_server        utf8mb4character_set_system        utf8character_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”。



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



结果插入正常,怀疑错误


此时回想数据来源,此数据是从 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




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


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



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



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



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


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

结语

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


发布于: 刚刚阅读数: 3
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
Oracle-TiDB迁移-生僻字乱码问题_迁移_TiDB 社区干货传送门_InfoQ写作社区