mtk 解决存储过程乱码问题

数据库及版本 字符集
源库 ORACLE 19.19 字符集
目标库 MogDB 5.0.5 ZHS16GBK

先看 MTK 的数据库迁移报告汇总页面

image-20240515093121497

开始时间是 2024-04-01 09:43:50 结束时间: 2024-04-02 16:55:29 ,历经 1天7小时,数据2.7T左右。

存储过程总共 164 个,失败了 90个。

点击查看详情,可以看到它的报错是:

失败原因:
code: 3F001 msg: schema “xxxxx” does not exist Line: 14 Position: 465

可以看到 out xxxxx.refCursor 这个是个包的名称,这里 mtk识别为schema的名称,这不是关键因素,继续查看,发现大部分存储过程都是汉字是乱码。

但是单独通过工具导出的存储过程汉字是正常的。

也就是 mtk 在获取存储过程的时候编码有问题。

注意 mtk 的字符集的设置有两个,一个是数据库的 charset,一个是客户端的 clientCharset

根据 https://docs.mogdb.io/zh/mtk/v2.0/mtk-config#clientcharset

clientCharset

类型: string
描述: 针对数据库编码转换场景使用,一般情况下不需要设置.

  1. 主动配置下会检查源和目标是否一致,不一致则同步源设置,一致不处理
  2. 默认根据源字符集进行设置,尽量减少转码次数。 如源Oracle是ZHS16GBK则以GBK读取,目标端以GBK插入,如果目标端是GBK则不需要转码,是UTF8则在数据库内核层转码不在驱动层转码

如 Oracle ZHS16GBK 编码迁移到 openGauss UTF8. 遇到ORA-29275: partial multibyte character.

还有一个是 :charset

charset

类型: string

描述: 数据库字符集.

默认不用配置,连接数据库查询.

可选值:

  • gbk
  • utf8

的描述,这俩参数很强大,可以不用设置,会自动判断,但是在实施的过程会发现,存储过程的汉字会乱码。常存储过程是通过 dba_source 来获取的,检查部署 mtk 的主机的 NLS_LANG 设置为空,通过sqllus 查询 dba_source发现是乱码,手工设置为 gbk,也是乱码,后来设置为 utf8 之后,查询出来的dba_source 正常。同时也设置了xshell终端的字符集等,查询 dba_source 也是乱码,只有设置 NLS_LANG 为 utf8,查询正常。

1
export  NLS_LANG=AMERICAN_AMERICA.AL32UTF8

为了确保 mtk 获取的存储过程不是乱码,建议在终端设置 NLS_LANG参数(NLS_LANG 不一定要跟数据库的字符集相同,见后面的oracle 官方文章的 关于 NLS_LANG 的常见误解:将 NLS_LANG 设置为数据库的字符集有可能正确,但大多数情况下都是不正确的请勿假设 NLS_LANG 必须与数据库字符集相同。事实往往并非如此。)之后,

如何检测呢,我这边测试就是通过sqlplus 查询 dba_source 如果汉字不乱码,然后执行mtk就正常。

源端 ORACLE 数据库的字符集是ZHS16GBK,但是 NLS_LANG 设置为 AMERICAN_AMERICA.AL32UTF8 是可以解决。设置为其他字符集比如跟数据库相同的字符集 ZHS16GBK 也是无法解决的。

之前总认为 NLS_LANG 的设置要跟数据库的字符集相同,后来查询资料发现这是错误的。https://www.oracle.com/cn/database/technologies/faq-nls-lang.html

关于 NLS_LANG 的常见误解

  • 将 NLS_LANG 设置为数据库的字符集有可能正确,但大多数情况下都是不正确的。请勿假设 NLS_LANG 必须与数据库字符集相同。事实往往并非如此。
  • 使用 NLS_LANG 参数定义字符集不会更改客户端的字符集。这是为了让 Oracle 知道您在客户端上所使用的字符集,以便 Oracle 可以做出正确的转换。如果您使用不同的 NLS_LANG 设置,这并不能更改客户端的字符集!
  • 如果未在客户端上设置 NLS_LANG,则它将使用服务器的 NLS_LANG。同样,这可能是不正确的!例如,如果 Oracle 安装程序未填充 NLS_LANG,并且该参数没有另行设置,则其默认值为 AMERICAN_AMERICA.US7ASCII。语言是 AMERICAN,区域是 AMERICA,字符集是 US7ASCII。
  • 设置 NLS_LANG 的 LANGUAGE 和 TERRITORY 参数与在数据库中存储字符的能力无关。如果将 NLS_LANG 设置为 JAPANESE_JAPAN.WE8MSWIN1252,由于 WE8MSWIN1252 不支持日语字符,因此不能存储日语。但是,将 NLS_LANG 设置为 AMERICAN_AMERICA.JA16SJIS 则可以存储日语,只要所输入的数据确实是 JA16SJIS,而且数据库也使用可以存储日语的字符集(如 UTF8 或 JA16SJIS)。

经过 设置之后,重新单独跑了mtk的存储过程,汇总页面有一些清爽了。接近 100%成功,其中1个识别和警告是源端数据库就是失效的存储过程。

image-20240516101439683 image-20240516101452738

以上的乱码应该不是 MTK 的问题,以上不设置的时候 sqlplus 也是乱码,设置了之后,sqlplus 不是乱码之后,mtk 的结果也不是乱码。关于 NLS_LANG 的知识,待日后补充。

附件:

*Table C-1 NLS_LANG Parameter Values*

Operating System Locale NLS_LANG Value
Arabic (U.A.E.) ARABIC_UNITED ARAB EMIRATES.AR8MSWIN1256
Bulgarian BULGARIAN_BULGARIA.CL8MSWIN1251
Catalan CATALAN_CATALONIA.WE8MSWIN1252
Chinese (PRC) SIMPLIFIED CHINESE_CHINA.ZHS16GBK
Chinese (Taiwan) TRADITIONAL CHINESE_TAIWAN.ZHT16MSWIN950
Croatian CROATIAN_CROATIA.EE8MSWIN1250
Czech CZECH_CZECH REPUBLIC.EE8MSWIN1250
Danish DANISH_DENMARK.WE8MSWIN1252
Dutch (Netherlands) DUTCH_THE NETHERLANDS.WE8MSWIN1252
English (United Kingdom) ENGLISH_UNITED KINGDOM.WE8MSWIN1252
English (United States) AMERICAN_AMERICA.WE8MSWIN1252
Estonian ESTONIAN_ESTONIA.BLT8MSWIN1257
Finnish FINNISH_FINLAND.WE8MSWIN1252
French (Canada) CANADIAN FRENCH_CANADA.WE8MSWIN1252
French (France) FRENCH_FRANCE.WE8MSWIN1252
German (Germany) GERMAN_GERMANY.WE8MSWIN1252
Greek GREEK_GREECE.EL8MSWIN1253
Hebrew HEBREW_ISRAEL.IW8MSWIN1255
Hungarian HUNGARIAN_HUNGARY.EE8MSWIN1250
Icelandic ICELANDIC_ICELAND.WE8MSWIN1252
Indonesian INDONESIAN_INDONESIA.WE8MSWIN1252
Italian (Italy) ITALIAN_ITALY.WE8MSWIN1252
Japanese JAPANESE_JAPAN.JA16SJIS
Korean KOREAN_KOREA.KO16MSWIN949
Latvian LATVIAN_LATVIA``.BLT8MSWIN1257
Lithuanian LITHUANIAN_LITHUANIA.BLT8MSWIN1257
Norwegian NORWEGIAN_NORWAY.WE8MSWIN1252
Polish POLISH_POLAND.EE8MSWIN1250
Portuguese (Brazil) BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252
Portuguese (Portugal) PORTUGUESE_PORTUGAL.WE8MSWIN1252
Romanian ROMANIAN_ROMANIA.EE8MSWIN1250
Russian RUSSIAN_CIS.CL8MSWIN1251
Slovak SLOVAK_SLOVAKIA.EE8MSWIN1250
Spanish (Spain) SPANISH_SPAIN.WE8MSWIN1252
Swedish SWEDISH_SWEDEN.WE8MSWIN1252
Thai THAI_THAILAND.TH8TISASCII
Spanish (Mexico) MEXICAN SPANISH_MEXICO.WE8MSWIN1252
Spanish (Venezuela) LATIN AMERICAN SPANISH_VENEZUELA.WE8MSWIN1252
Turkish TURKISH_TURKEY.TR8MSWIN1254
Ukrainian UKRAINIAN_UKRAINE.CL8MSWIN1251
Vietnamese VIETNAMESE_VIETNAM.VN8MSWIN1258

原文作者: Hi.MogDB

原文链接: https://hi.mogdb.org/posts/f4a90812/

许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议