探索 Oracle 之 EXP/IMP 过程中的字符集问题
1. 问题描述
Oracle 数据库之间的数据迁移是一个很常见的作业,EXP/IMP 工具是一个常用的数据迁移及转化工具,因其导出文件具有平台无关性,所以在跨平台迁移中,最为常用。但在实际操作过程中,涉及到源数据库,客户端,目标数据库三方面的字符集问题。
操作人员对三者之间的字符集转换过程不了解,而冒然使用 EXP/IMP 命令,往往在迁移过程中报错终止,或是在没有报错的情况下成功导入,但其背后却存在隐患,在查询时经常显示乱码。
2. 解决方法
2.1 源端数据库(1)→ EXP 客户端(2)→ IMP 客户端(3)→ 目标数据库(4),数据在迁移过程中要经历如上的 4 个点,数据在流动过程中(如上的 3 个箭头)需要依次比较箭头两端的字符集,如果相同则不转换,如果不同则进行转换。如果相邻的两个点之间设置的字符集均不相同,则需要转换 3 次。
根据上述理论分析,最好的设置方式是,因为(1)(4)数据库的字符集是固定的,则设置客户端的字符集(2)(3)均与(1)相同,这样最多只在(3)→(4)的过程中发生一次字符集的转换。但是前提是(4)的字符集必须是(1)的的字符集的超集。客户端字符集是通过环境变量 NLS_LANG 来设置。
- Linux:
export NLS_LANG=SIMPLIFIEDCHINESE_CHINA.ZHS16GBK
- Windows:
set NLS_LANG=SIMPLIFIEDCHINESE_CHINA.ZHS16GBK
EXP 导出的文件,可以通过 WINDOWS 上的工具 UE 来查看,其中第一行的第 2、3 个字节显示的数字代表了文件的字符集。在 sqlplus 里通过 select nls_charset_name() from dual;
可以查看该数字代表的字符集。
03 03 54 45 58 50 4F 52 54 3A
其中,03 54 是 16 进制的数字,代表了一种字符集。将其转换为 10 进制为:
SQL> select to_number('0354','xxxx') from dual;
TO_NUMBER('0354','XXXX')
------------------------
852
查询 852 代表的字符集
SQL> select nls_charset_name(852) from dual;
NLS_CHAR
--------
ZHS16GBK
当然还可以逆向操作
SQL> select nls_charset_id('ZHS16GBK') from dual;
NLS_CHARSET_ID('ZHS16GBK')
--------------------------
852
2.2 ORACLE 在 10g 以后的版本中提供了新的迁移工具 EXPDP/IMPDP,此工具无需设置客户端字符集,而是由 ORACLE 自动去识别并完全字符集的转换。这是因为 EXPDP/IMPDP 并不是完整意义上的客户端,它和 EXP/IMP/sqlplus 并不完全一样。它只是向 oracle 传输了一个命令,oracle 在内部生成一个任务,文件只能导出在服务器上,而不能像 exp/imp 一样将文件导出到远程端。但前提依然是,目标数据库的字符集应是源数据库字符集的超集。
其实,在使用 exp/imp、expdp/impdp 时,并不一定要严格要求目的数据库是源数据库的超集。问题的关键之处在于源端的字符能在目的端找到对应的字符。在不同字符集的数据库传输之前,我们最好通过 oracle 提供的 csscan 工具来检查两个字符集之间是否可以转换。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论