Oracle字符集研究ppt课件
- ORACLE字符集研讨 Dextrys Co., Ltd. Kelson Cong DBA Team
飞刀,又见飞刀什么是字符集?字符集就是按照一定的字符编码方案,对一组特定的符号,分别赋予不同数值编码的集合。Oracle数据库最早支持的编码方案是US7ASCII。Oracle的字符集命名遵照以下命名规则:比如ZHS16GBK表示采用GBK编码格式、16位两个字节简体中文字符集。飞刀,又见飞刀字符编码方案有单字节编码和多字节编码两种。单字节编码是指单字节7位字符集,可以定义128个字符,最常用的字符集为US7ASCII;单字节8位字符集,可以定义256个字符,适宜于欧洲大部分国家,例如WE8ISO8859P1(西欧、8位、ISO规范8859P1编码)。飞刀,又见飞刀多字节编码是指变长多字节编码,某些字符用一个字节表示,其它字符用两个或多个字符表示,常用于对亚洲言语的支持,例如日语、汉语、印地语等,例如AL32UTF8。其中AL代表ALL,指适用于一切言语,ZHS16CGB231280是定长多字节编码,每一个字符都运用固定长度字节的编码方案,目前Oracle独一支持的定长多字节编码是AF16UTF16,也是仅用于国家字符集。飞刀,又见飞刀Unicode编码是一个涵盖了目前全世界运用的一切知字符的单一编码方案,也就是说Unicode为每一个字符提供独一的编码。UTF-16是Unicode的16位编码方式,是一种定长多字节编码,用2个字节表示一个Unicode字符,AF16UTF16是UTF-16编码字符集。UTF-8是Unicode的8位编码方式,是一种变长多字节编码,这种编码可以用1、2、3个字节表示一个Unicode字符,AL32UTF8、UTF8、UTFE是UTF-8编码字符集。当一种字符集A的编码数值包含一切另一种字符集B的编码数值,并且两种字符集一样编码数值代表一样的字符时,那么字符集A是字符集B的超级,或称字符集B是字符集A的子集。Oracle8i和Oracle9i官方文档资料中备有子集-超级对照表,例如WE8ISO8859P1是WE8MSWIN1252的子集。由于US7ASCII是最早的Oracle数据库编码格式,因此有许多字符集是US7ASCII的超集,例如WE8ISO8859P1、ZHS16CGB231280、ZHS16GBK都是US7ASCII的超集。巨匠的网站上提供了超集子集对照表(eygle/archives/2004/09/charactersetsubsetsuperset.html)查看字符集的工具:LBUILDER数据库字符集、数据库字符集Oracle效力器端字符集、数据库字符集在创建数据库时指定,在创建后通常不能更改。在创建数据库时,可以指定字符集(CHARACTER SET)和国家字符集(NATIONAL CHARACTER SET)。数据库字符集用来存储CHAR、VARCHAR2、CLOB、LONG等类型数据,用来标示诸如表名、列名以及PL/SQL变量等,用来存储SQL和PL/SQL程序单元等。数据库字符集国家字符集用以存储NCHAR、NVARCHAR2、NCLOB等类型数据。国家字符集本质上是为Oracle选择的附加字符集,主要作用是为了加强Oracle的字符处理能力,由于NCHAR数据类型可以提供对亚洲运用定长多字节编码的支持,而数据库字符集则不能。国家字符集在Oracle9i中进行了重新定义,只能在Unicode编码中的AF16UTF16和UTF8中选择,默许值是AF16UTF16。
- 数据库字符集讨论:
- 什么情况下用CHAR,NCHAR?
- 如何决定数据库字符集?
数据库字符集可以查询以下数据字典或视图查看字符集设置情况:nlsdatabaseparameters、props$、v$nlsparameters。查询结果中NLSCHARACTERSET表示字符集,NLSNCHARCHARACTERSET表示国家字符集。
数据库字符集如何修正效力器端字符集: Alter database character set ZHS16GBK(此方法慎用!千万不要经过)。
- 修正PROPS$的方式修正新的字符集一定是老字符集的超集。
数据库字符集客户端字符集: 客户端字符集定义了客户端字符数据的编码方式,任何发自或发往客户端的字符数据均运用客户端定义的字符集编码。客户端可以看作是能与数据库直接衔接的各种运用,客户端字符集是经过设置NLS_LANG参数来设定的。
客户端字符集NLSLANG参数格式: NLSLANG=LANGUAGE_TERRITORY.CHARACTERSET Language: 显示Oracle信息、校验、日期命名 Territory: 指定默许日期、数字、货币等格式 Client character set: 指定客户端将运用的字符集
例如:NLSLANG=AMERICANAMERICA.US7ASCII,AMERICAN是言语,AMERICA是地域,US7ASCII是客户端字符集。
客户端字符集设置方法:
UNIX环境:$NLSLANG="simplified chinesechina.zhs16gbk",$export NLS_LANG,编辑Oracle用户的profile文件。
Windows环境:编辑注册表 HKEYLOCALMACHINE-SOFTWARE-ORACLE-HOME0(9i)、HKEYLOCALMACHINE-SOFTWARE-ORACLE-KEYOraDb10ghome1(10g)。
客户端字符集字符集转换: 在EXP/IMP时存在的字符集转换:
源数据库字符集
Export过程中用户会话字符集经过NLS_LANG设定
Import过程中用户会话字符集经过NLS_LANG设定
目的数据库字符集
字符集转换导出的转换过程: 在Export过程中,假设源数据库字符集与Export用户会话字符集不一致,会发生字符集转换,并在导出文件的头部几个字节中存储Export用户会话字符集的ID号。在这个转换过程中可能会发生数据的丧失。例如,假设源数据库运用ZHS16GBK,而Export用户会话字符集运用US7ASCII,由于ZHS16GBK是16位字符集,而US7ASCII是7位字符集,这个转换过程中,中文字符在US7ASCII中无法找到对应的字符,所以所有中文字符都会丧失而变成"?",这样转换后生成的Dmp文件已经发生了数据丧失。因此,如果想正确导出源数据库数据,那么Export过程中用户会话字符集应等于源数据库字符集或是源数据库字符集的超集。
字符集转换导入的转换过程:
- 确定导出数据库字符集环境,通过读取导出文件头,可以获得导出文件的字符集设置。
- 确定导入session的字符集,即导入Session运用的NLS_LANG环境变量。
- IMP读取导出文件,读取导出文件字符集ID,和导入进程的NLS_LANG进行比较。
- 假设导出文件字符集和导入Session字符集一样,那么在这一步骤内就不需要转换。假设不同,就需要把数据转换为导入Session运用的字符集。可以看出,在导入数据到数据库过程中发生两次字符集转换:
- 第一次:导入文件字符集与导入Session运用的字符集之间的转换,假设这个转换过程不能正确完成,Import向目的数据库的导入过程也就不能完成。
- 第二次:导入Session字符集与数据库字符集之间的转换。
字符集转换假设源字符集和目的字符集一致,那么保证全部客户端一致。假设源和目的不一致,那么保证导入和导出客户端一致,且与源或者目的保持一致。
为了防止在数据库迁移过程中由于字符集不同导致的数据损失,Oracle提供了字符集扫描工具Character Set Scanner,通过这个工具我们可以测试在数据迁移过程中由于字符集转换可能带来的问题,然后根据测试结果,确定数据迁移过程中最正确的字符集处理方案。
字符集转换: 使用sysdba用户登录执行$ORACLE_HOME/rdbms/admin/csminst.sql,然后退回到命令提示符执行csscan FULL=Y FROMCHAR=WE8ISO8859P1 TOCHAR=UTF8 log=check.log capture=y array=1000000 process=2。执行终了以后查看log文件,可以知道哪些转换会失败。
字符集转换OS字符集: OS字符集以及OS字符集在字符集转换中起的作用。
查看OS字符集: OS字符集DEMO: 环境:OS: WINXP SP2 中文版,ORACLE 10.2.0.1效力器和客户端在一台机器上。 效力器字符集:AL32UTF8,国家字符集AL16UTF16。 客户端字符集:AL32UTF8。
以下是在SQLPLUS里面的操作: OS字符集SQL create table test (a varchar2(10)); SQL insert into test values ('我'); SQL commit; SQL select a, dump(a) from test;
可以看到,效力器端和客户端都是UTF8,但是显示出来的提示全部是乱码。再看一下汉字"我"的编码,查了一下编码表,在ZHS16GBK里面是206 98,在UTF8里面是230 145,在UTF16里面应该是98 17。但是实际的值是什么呢?实际的编码值是206 210,既不是GBK,也不是UTF8和UTF16的编码,查了一下其他的编码表,最终发现206 210是GB2312中"我"的编码。
OS字符集接着把数据库客户端编码切换成ZHS16GBK,看看会发生什么: SQL insert into test values ('我'); 已创建 1 行。 SQL select a, dump(a) from test;
可以发现,数据库在插入时,准确地把"我"字转换成UTF8的编码,并在显示的时候又转换成了准确的汉字"我"。怎样解释上面这个景象呢?
OS字符集经过实验我们可以发现,OS的字符集实际是GB2312的,但是由于客户端字符集和效力器端字符集一致,所以在上传数据的时候,以为不存在字符集转换,所以就直接把OS的汉字编码上传上去了,这也是我们看到的库中实际存放的是GB2312中"我"字编码206 210的缘由,显示的时候同样的方式,以为数据库效力器与客户端字符集编码一致,不存在字符集转换,于是把206 210发到客户端,到了客户端,就正好原封不动地把206 210显示成了汉字"我"。这也是呵斥提示乱码的缘由,让GBK的窗口去解析UTF8的编码,从而产生乱码。
OS字符集当客户端字符集是GBK的时候,执行INSERT的时候,Oracle认识到效力器与客户端字符集不一致,产生一次字符集转换,把"我"字转换成UTF8编码230,145存入数据库中,SELECT的时候做反操作,将UTF8转换成GBK编码显示出来。
OS字符集经典"靠"问题: OS字符集在一个中文系统中所有的汉字全部显示为"靠"。
DEMO: 效力器端:ZHS16GBK 客户端:WE8ISO8859P1 OS:GBK
OS字符集库里存在汉字"我",是从辉客户端做SELECT时,Oracle判别效力器客户端字符集不一致,于是做字符集转换,西欧字符集里面是没有汉字,转换成特殊编码,变成问号,编码为BF。客户端得到"BF BF BF BF"。
OS是GBK,以为是两个汉字,"BFBF","BFBF"最终显示结果"靠靠!QA