Oracle NLS_LANG小结

从客户那里拿到一个数据库,客户的数据库Server的字符集是JA16SJIS,使用export的Client端的NLS_LANG是US7ASCII。问过DBA,得到的结论是由于Client使用的字符集是Server字符集的子集,所以导出的dump文件应该无效,以前也看过一本《循序渐进Oracle》,从那本书的说的情况看也应该是有问题的。但是自己还是试了试,报了很多错“长度不够”,原因是我的Oracle Instance字符集是AL32UTF8,没办法重新建了个JA16SJIS数据库,Console的NLS_LANG设置为AMERICAN_AMERICA.US7ASCII,成功导入!表中的日文字符都没有问题。

很奇怪为什么能成功导入,做了个是试验:

创建了一个Test表,包含日文字符。
导出两次,NLS_LANG分别是AMERICAN_AMERICA.US7ASCII和AMERICAN_AMERICA.JA16SJIS,对比两次导出的dump文件,发现只有文件头不一样,其余部分基本一致,尤其是建表和插入的数据二进制部分完全一样。NLS_LANG的设置可能不会影响dump文件的编码。通过查询Oracle网站得到这样的一句话

In Oracle9i the Export utility always exports user data, including Unicode data, in the character set of the database. The Import utility automatically converts the data to the character set of the target database.

也就是说,dump文件的数据的编码和源数据库的相同,不管Client的NLS_LANG如何设置。如果源数据库的字符集和目标数据库的字符集不一致,import时会自动转换。当然在不一致的情况下,源数据库的字符集一定要是目标数据库的子集。再查了下《循序渐进Oracle》,书中关于导入导出的例子使用的Oracle 8i,应该是作者偷懒把上一版的内容直接拿过来没更新。

另外再Oracle提供的关于NLS_LANG FAQ也列出了几条对NLS_LANG误解:

“NLS_LANG和数据库的字符集一样或许是正确的,但是经常是不对的。不要认为NLS_LANG必须和数据库的字符集一样,这经常是错的。” 《循序渐进Oracle》中说NLS_LANG一样的话可以提高性能,因为不需要字符集的转换。其实这样的转换不时发生在Server端,Client端转换完成后传递给Server端。我觉得,只要NLS_LANG是Server的字符集的子集就可以。

“NLS_LANG的字符集设置不会更改Client端的字符集。它只是用来告诉Oracle你在Client端使用什么字符集,你不能通过设置NLS_LANG去影响Client的字符集”。而且如果Client端的字符集和NLS_LANG不兼容,会导致数据库乱码。

“如果你不在Client端设置NLS_LANG,那么默认会使用Server的NLS_LANG设置,这是错的。如果Oracle在安装时没有设置NLS_LANG,那么NLS_LANG不会另外再设置,而是使用默认值:AMERICAN_AMERICA.US7ASCII。语言是AMERICAN,区域是AMERICA,字符集US7ASCII”

“设置NLS_LANG的LANGUAGE 和 TERRITORY部分不会影响存储在数据库的字符。将NLS_LANG设置为JAPANESE_JAPAN.WE8MSWIN1252不会允许你存储日文。因为WE8MSWIN1252字符集不支持日文。但是设置成AMERICAN_AMERICA.JA16SJIS会允许你存储日文,假设你输入的字符是JA16SJIS,并且数据库的字符集也支持日文(如UTF8或者JA16SJIS)”


还需要注意的是:

SELECT USERENV ('language') FROM DUAL返回的是Session的LANGUAGE和 TERRITORY数据库的字符集。

参考:http://www.oracle.com/technology/tech/globalization/htdocs/nls_lang%20faq.htm

你可能感兴趣的:(oracle)