乐观 发表于 2015-1-16 22:35:28

MSSQL编程:字符集成绩的开端切磋(六)-----乱码的产...

Mysql的存储引擎接口定义良好。有兴趣的开发者可以通过阅读文档编写自己的存储引擎。成绩

原文链接:


http://www.eygle.com/special/NLS_CHARACTER_SET_06.htm




原文宣布于itpub手艺丛书《Oracle数据库DBA专题手艺精炼》,未经允许,严禁转载本文.

最初我们来会商一下乱码的发生。



一般在我们的实际情况中,存在3个字符集设置。

第一:客户端使用字符集(ClientApplicationCharacterSet)

第二:客户端NLS_LANG参数设置

第三:服务器端,数据库字符集(CharacterSet)设置



我们说,一个字符在客户端使用(好比SQLPLUS,CMD,NOTEPAD等)中以如何的字符显现取决于客户端操纵体系,客户端可以显现如何的字符,
我们就能够在使用中录进这些字符,至于这些字符可否在数据库中一般存储,就和别的的两个字符集设置严密相干了。

在传输过程当中,客户端NLS_LANG次要用于举行转换判别

假如NLS_LANG即是数据库字符集,则不举行任何转换间接把字符拔出数据库

假如分歧则举行转换,转换次要有两个义务
假如存在对应干系,则把响应二进制编码经由映照后(这一步映照今后,所代表的字符大概产生转换)传送给数据库假如不存在对应干系,则传送一个交换字符(良多平台就是?)


数据库字符集,在和客户端NLS_LANG分歧时,会把经由NLS_LANG转换的字符举行进一步处置
关于?(即不存在对应干系的字符)间接以?情势寄存进数据库关于其他字符,在NLS_LANG和数据库字符集之间举行转换后存进。


以下我们来看一下最为罕见的字符集及乱码的发生:

1.当NLS_LANG字符集与数据库字符集分歧,同时NLS_LANG分歧于Server端字符集设置

在这类情形下,存在两种大概:
客户端输出的字符在NLS_LANG中没有对应的字符,这时候没法转换,NLS_LANG利用交换字符替换这些没法映照的字符(这一步转换在TTS中
完成),在良多字符会合这个替换字符就是”?”当客户真个字符在NLS_LANG中对应了分歧的字符时,传送给数据库今后产生转换,存储的是字符,可是已丧失了元数据,数据库中
的字符不再代表客户真个输出。并且这个历程不成逆,这也就是为何良多时分在客户端输出的是一般的编码,查询以后会失掉未知字符的缘故原由。


我们经由过程上图来复杂申明一下这个历程,当客户端在WE8ISO8859P15字符集时,输出欧元标记:€,这时候客户端NLS_LANG和数据库端字符集分歧,
举行第一次转换,客户端€标记编码是A4,在NLS_LANG转换时,A4对应了NLS_LANG中的‘¤’,这一步的转换发生了毛病映照。因为数据库字符集不
同于NLS_LANG设置,这时候进一步的转换产生了,存进数据库的编码酿成了C2A4,固然同NLS_LANG举行了准确的转换,可是客户端录进的数据已
破坏大概丧失了。

我们能够用我们熟习的字符集做一个复杂的测试:

测试情况:

客户端使用为中文18030字符集

NLS_LANG设置为US7ASCII字符集

数据库CHARACTERSET为ZHS16GBK



c:>setNLS_LANG=AMERICAN_AMERICA.US7ASCIIc:>sqlpluseygle/eygleSQL*Plus:Release9.2.0.4.0-ProductiononTueNov401:19:572003Copyright(c)1982,2002,OracleCorporation.Allrightsreserved.Connectedto:Oracle9iEnterpriseEditionRelease9.2.0.4.0-ProductionWiththePartitioning,OracleLabelSecurity,OLAPandOracleDataMiningoptionsJServerRelease9.2.0.4.0-ProductionSQL>insertintotestvalues(测试);1rowcreated.SQL>selectname,dump(name)fromtest;NAMEDUMP(NAME)--------------------------------------------------2bJTTyp=1Len=4:50,98,74,84这时候候我们发明,查询出来的是凌乱的字符,我们把这些字符转换为2进制就是110010110001010010101010100补全8位就是00110010011000100100101001010100我们把首位换成110110010111000101100101011010100我们来看准确的存储:
c:>setnls_lang=AMERICAN_AMERICA.ZHS16GBK

c:>sqlpluseygle/eygle

SQL*Plus:Release9.2.0.4.0-ProductiononTueNov401:40:182003

Copyright(c)1982,2002,OracleCorporation.Allrightsreserved.


Connectedto:
Oracle9iEnterpriseEditionRelease9.2.0.4.0-Production
WiththePartitioning,OracleLabelSecurity,OLAPandOracleDataMiningoptions
JServerRelease9.2.0.4.0-Production

SQL>insertintotestvalues(测试);

1rowcreated.

SQL>coldump(name)fora30
SQL>selectname,dump(name)fromtest;

NAMEDUMP(NAME)
----------------------------------------
测试Typ=1Len=4:178,226,202,212

1rowselected.


我们把这个了局转换为2进制暗示
10110010111000101100101011010100

这个了局恰是我们后面乱码首位补全1后的了局。

这个测试申明在US7ASCII转换中文的时分撤除了首位的1,如许就丧失了元数据,招致乱码呈现,NLS_LANG的转换感化由此可加一斑!




3.NLS_LANG和数据库字符集不异时
在这类情形下,数据库端对客户端传送过去的编码不举行任何转换(如许能够进步功能),间接存储进进数据库,那末这时候候就存在和下面一样的成绩,
假如客户端传送过去的字符集在数据库中有准确的对应就能够准确存储,假如没有,就会被交换字符置换成?,乱码就如许发生了。




如上图所示,当NLS_LANG和数据库字符集设置不异都为UTF8时,客户真个欧元标记的编码A4就不会经由任何转换就拔出到数据库中,而在UTF8的数
据库中,A4代表的是一个不法字符。



我们来看一个复杂的测试

测试情况:

客户端字符集使用为中文GB18030

客户端NLS_LANG为US7ASCII

数据库字符集为US7ASCII
我们晓得这个时分,存进的数据,数据库不举行任何转换,在以下的测试中,我们看到中文在US7ASCII字符集下得以准确显现。




c:>setnls_lang=AMERICAN_AMERICA.US7ASCIIc:>sqlpluseygle/eygleSQL*Plus:Release9.2.0.4.0-ProductiononTueNov401:02:042003Copyright(c)1982,2002,OracleCorporation.Allrightsreserved.Connectedto:Oracle9iEnterpriseEditionRelease9.2.0.4.0-ProductionWiththePartitioning,OracleLabelSecurity,OLAPandOracleDataMiningoptionsJServerRelease9.2.0.4.0-ProductionSQL>insertintotestvalues(测试);1rowcreated.SQL>commit;Commitcomplete.SQL>select*fromtest;NAME----------测试1rowselected.SQL>coldump(name)fora30SQL>selectname,dump(name)fromtest;NAMEDUMP(NAME)----------------------------------------测试Typ=1Len=4:178,226,202,2121rowselected.SQL>select*fromnls_database_parameters;PARAMETERVALUE----------------------------------------------------------------------NLS_LANGUAGEAMERICANNLS_TERRITORYAMERICANLS_CURRENCY$NLS_ISO_CURRENCYAMERICANLS_NUMERIC_CHARACTERS.,NLS_CHARACTERSETUS7ASCIINLS_CALENDARGREGORIANNLS_DATE_FORMATDD-MON-RRNLS_DATE_LANGUAGEAMERICANNLS_SORTBINARYNLS_TIME_FORMATHH.MI.SSXFFAMPARAMETERVALUE----------------------------------------------------------------------NLS_TIMESTAMP_FORMATDD-MON-RRHH.MI.SSXFFAMNLS_TIME_TZ_FORMATHH.MI.SSXFFAMTZRNLS_TIMESTAMP_TZ_FORMATDD-MON-RRHH.MI.SSXFFAMTZRNLS_DUAL_CURRENCY$NLS_COMPBINARYNLS_LENGTH_SEMANTICSBYTENLS_NCHAR_CONV_EXCPFALSENLS_NCHAR_CHARACTERSETAL16UTF16NLS_RDBMS_VERSION9.2.0.4.020rowsselected.SQL>



结语:

关于DBA来讲,有一个很主要的准绳就是:不要把你的数据库置于伤害的地步!

这就请求我们,在举行任何大概对数据库布局产生改动的操纵之前,先做无效的备份,良多DBA没有备份的操纵中失掉了凄惨的教导。
恢复到之前的某个状态,是需要数据的。这数据可以是a)回滚步骤或者b)操作之前的数据状态原文。

小魔女 发表于 2015-1-19 17:53:37

一个是把SQL语句写到客户端,可以使用DataSet进行加工;

活着的死人 发表于 2015-1-19 17:53:37

作了些试验,发现使用CLR的存储过程或函数在达到一定的阀值的时候,系统性能会呈指数级下滑!这是非常危险的!只使用几个可能没有问题,当一旦大规模使用会造成严重的系统性能问题!

兰色精灵 发表于 2015-2-4 13:21:56

原来的计算字段其实和虚拟字段很像。只是管理方面好了而已,性能方面提高不多。但是SQL2005提供了计算字段的持久化,这就提高了查询的性能,但是会加重insert和update的负担。OLTP慎用。OLAP可以大规模使用。

透明 发表于 2015-2-9 23:34:58

一直以来个人感觉SQLServer的优化器要比Oracle的聪明。SQL2005的更是比2k聪明了不少。(有次作试验发现有的语句在200万级时还比50万级的相同语句要快show_text的一些提示没有找到解释。一直在奇怪。)

谁可相欹 发表于 2015-2-28 07:27:59

入门没那么困难,精通没那么容易

小女巫 发表于 2015-3-17 01:25:21

原来公司用过MYSQL自己也只是建个表写个SQL

变相怪杰 发表于 2015-3-23 14:50:56

你觉得我的非分区索引无法对起子分区,你可以提醒我一下呀!没有任何的提醒,直接就变成了非分区表。不知道这算不算一个bug。大家也可以试试。
页: [1]
查看完整版本: MSSQL编程:字符集成绩的开端切磋(六)-----乱码的产...