仓酷云

标题: MYSQL网页设计Oracle数据库字符集成绩剖析 zz [打印本页]

作者: 小妖女    时间: 2015-1-16 22:41
标题: MYSQL网页设计Oracle数据库字符集成绩剖析 zz
只需每年花费2000到5000美元。无论你是自掏腰包来创建一个新兴公司,还是得到了风险投资商的赞助,使用MySQL都可以降低你所需要的人力成本。oracle|数据|数据库|成绩
常常看到一些伴侣问ORACLE字符集方面的成绩,我想以迭代的体例来先容一下。

第一次迭代:把握字符集方面的基础观点。
有些伴侣大概会以为这是画蛇添足,但实践上恰是因为对相干基础观点掌控不清,才招致了诸多成绩和疑问。
起首是字符集的观点。
我们晓得,电子盘算机最后是用来举行迷信盘算的(以是叫做“盘算机”),但跟着手艺的开展,还必要盘算机举行别的方面的使用处置。这就请求盘算机不但能处置数值,还能处置诸如笔墨、特别标记等别的信息,而盘算机自己能间接处置的只要数值信息,以是就请求对这些笔墨、标记信息举行数值编码,最后的字符集是我们都十分熟习的ASCII,它是用7个二进制位来暗示128个字符,尔后来跟着分歧国度、构造的必要,呈现了许很多多的字符集,如暗示西欧字符的ISO8859系列的字符集,暗示汉字的GB2312-80、GBK等字符集。
字符集的本色就是对一组特定的标记,分离付与分歧的数值编码,以便于盘算机的处置。
字符集之间的转换。字符集多了,就会带来一个成绩,好比一个字符,在某一字符会合被编码为一个数值,而在另外一个字符会合被编码为另外一个数值,好比我来制造两个字符集demo_charset1与demo_charset2,在demo_charset1中,我划定了三个标记的编码为:A(0001),B(0010),?(1111);而在demo_charset2中,我也划定了三个标记的编码为:A(1001),C(1011),?(1111),这时候我接到一个义务,要编写一个程序,卖力在demo_charset1与demo_charset2之间举行转换。因为晓得两个字符集的编码划定规矩,关于demo_charset1中的0001,在转换为demo_charset2时,要将其编码改成1001;关于demo_charset1中的1111,转换为demo_charset2时,其数值稳定;而关于demo_charset1中的0010,其对应的字符为B,但在demo_charset2没有对应的字符,以是从实际上没法转换,关于一切这类没法转换的情形,我们能够将它们一致转换为方针字符会合的一个特别字符(称为“交换字符”),好比在这里我们能够将?作为交换字符,以是B就转换为了?,呈现了信息的丧失;一样事理,将demo_charset2的C字符转换到demo_charset1时,也会呈现信息丧失。
以是说,在字符集转换过程当中,假如源字符会合的某个字符在方针字符会合没有界说,将会呈现信息丧失。
数据库字符集的选择。
我们在创立数据库时,必要思索的一个成绩就是选择甚么字符集与国度字符集(经由过程createdatabase中的CHARACTERSET与NATIONALCHARACTERSET子句指定)。思索这个成绩,我们必需要分明数据库中都必要存储甚么数据,假如只必要存储英文信息,那末选择US7ASCII作为字符集就能够;可是假如要存储中文,那末我们就必要选择可以撑持中文的字符集(如ZHS16GBK);假如必要存储多国言语笔墨,那就要选择UTF8了。
数据库字符集切实其实定,实践上申明这个数据库所能处置的字符的汇合及其编码体例,因为字符集选定后再举行变动会有诸多的限定,以是在数据库创立时必定要思索分明后再选择。
而我们很多伴侣在创立数据库时,不思索分明,常常选择一个默许的字符集,如WE8ISO8859P1或US7ASCII,而这两个字符集都没有汉字编码,以是用这类字符集存储汉字信息从准绳上说就是毛病的。固然在有些时分选用这类字符集好象也能一般利用,但它会给数据库的利用与保护带来一系列的贫苦,在前面的迭代过程当中我们将深切剖析。
客户真个字符集。
有过一些Oracle利用履历的伴侣,年夜多会晓得经由过程NLS_LANG来设置客户真个情形,NLS_LANG由以下部分构成:NLS_LANG=<Language>_<Territory>.<ClientsCharacterset>,个中第三部分<ClientsCharacterset>的本意就是用来指明客户端操纵体系缺省利用的字符集。以是按正轨的用法,NLS_LANG应当依照客户端呆板的实践情形举行设置,特别关于字符集一项更是云云,如许Oracle就可以够在最年夜水平上完成数据库字符集与客户端字符集的主动转换(固然是假如必要转换的话)。
总结一下第一次迭代的重点:
字符集:将特定的标记集编码为盘算性能够处置的数值;
字符集间的转换:关于在源字符集与方针字符集都存在的标记,实际上转换将不会发生信息丧失;而关于在源字符会合存在而在方针字符会合不存在的标记,实际上转换将会发生信息丧失;
数据库字符集:选择可以包括一切将要存储的信息标记的字符集;
客户端字符集设置:指明客户端操纵体系缺省利用的字符集。



第二次迭代:经由过程实例加深对基础观点的了解

上面我将援用网友tellin在ITPUB上宣布的“CHARACTERSET研讨及疑问”帖子,该伴侣在帖子中枚举了他做的相干实行,并对实行了局提出了一些疑问,我将对他的实行了局举行剖析,并回覆他的疑问。
实行了局剖析一
quote:最后由tellin公布
设置客户端字符集为US7ASCII
D:>SETNLS_LANG=AMERICAN_AMERICA.US7ASCII
检察服务器字符集为US7ASCII
SQL>SELECT*FROMNLS_DATABASE_PARAMETERS;
PARAMETERVALUE
----------------------------------------------------------------------
NLS_CHARACTERSETUS7ASCII

创建测试表
SQL>CREATETABLETEST(R1VARCHAR2(10));

Tablecreated.

拔出数据
SQL>INSERTINTOTESTVALUES(西南);

1rowcreated.

SQL>SELECT*FROMTEST;

R1
----------
西南

SQL>EXIT




这一部分的实行数据的存取与显现都准确,好象没甚么成绩,但实践上却埋没着很年夜的隐患。
起首,要将汉字存进数据库,而将数据库字符集设置为US7ASCII是分歧适的。US7ASCII字符集只界说了128个标记,其实不撑持汉字。别的,因为在SQL*PLUS中可以输出中文,操纵体系缺省应当是撑持中文的,但在NLS_LANG中的字符集设置为US7ASCII,明显也是不准确的,它没有反应客户真个实践情形。
但实践显现倒是准确的,这次要是由于Oracle反省数据库与客户真个字符集设置是一样的,那末数据在客户与数据库之间的存取过程当中将不产生任何转换。详细地说,在客户端输出“西南”,“东”的汉字的编码为182(10110110)、171(10101011),“北”汉字的编码为177(10110001)、177(10110001),它们将不做任何变更的存进数据库中,可是这实践上招致了数据库标识的字符集与实践存进的内容是不符合的,从某种意义上讲,这也是一种纷歧致性,也是一种毛病。而在SELECT的过程当中,Oracle一样反省发明数据库与客户真个字符集设置是不异的,以是它也将存进的内容一成不变地传送到客户端,而客户端操纵体系辨认出这是汉字编码以是可以准确显现。
在这个例子中,数据库与客户真个设置都有成绩,但却好象起到了“负负得正”的效果,从使用的角度看倒好象没成绩。但这内里却存在着极年夜的隐患,好比在使用length或substr等字符串函数时,便可能失掉不测的了局。别的,假如碰到导进/导出(import/export)将会碰到更年夜的贫苦。有些伴侣在这方面做了大批的测试,如eygle研讨了“源数据库字符集为US7ASCII,导出文件字符集为US7ASCII或ZHS16GBK,方针数据库字符集为ZHS16GBK”的情形,他得出的结论是“假如的是在Oracle92中,我们发明关于这类情形,不管如何处置,这个导出文件都没法准确导进到Oracle9i数据库中”、“关于这类情形,我们能够经由过程利用Oracle8i的导收工具,设置导出字符集为US7ASCII,导出后修正第2、三字符,修正0001为0354,如许就能够将US7ASCII字符集的数据准确导进到ZHS16GBK的数据库中”。我想关于这些结论,如许了解大概更符合一些:因为ZHS16GBK字符集是US7ASCII的超等,以是假如按一般操纵,这类转换应当没有成绩;但呈现成绩的实质是我们让本应只存储英笔墨符的US7ASCII数据库,十分规地存储了中文信息,那末在转化过程当中呈现毛病或贫苦就没甚么奇异的了,不出贫苦却是有些奇异了。
以是说要制止这类情形,就是要在创建数据库时选择符合的字符集,不让标签(数据库的字符集设置)与实践(数据库中实践存储的信息)不符的情形产生。



实行了局剖析二

quote:[变动客户端字符集为ZHS16GBK
D:>SETNLS_LANG=AMERICAN_AMERICA.ZHS16GBK

D:>SQLPLUS"/ASSYSDBA"

没法一般显现数据

SQL>SELECT*FROMTEST;

R1
--------------------
6+11

疑问1:ZHS16GBK为US7ASCII的超集,为何在ZHS16GBK情况下没法一般显现




这次要是由于Oracle反省发明数据库设置的字符集与客户端设置字符集分歧,它将对数据举行字符集的转换。数据库中实践寄存的数据为182(10110110)、171(10101011)、177(10110001)、177(10110001),因为数据库字符集设置为US7ASCII,它是一个7bit的字符集,存储在8bit的字节中,则Oracle疏忽各字节的最高bit,则182(10110110)就酿成了54(0110110),在ZHS16GBK中代表数字标记“6”(固然在别的字符会合也是“6”),一样历程也产生在别的3个字节,如许“西南”就酿成了“6+11”。

实行了局剖析三

quote:最后由tellin公布
用ZHS16GBK拔出数据
SQL>INSERTINTOTESTVALUES(西南);

1rowcreated.

SQL>SELECT*FROMTEST;

R1
--------------------
6+11
??

SQL>EXIT


当客户端字符集设置为ZHS16GBK后向数据库拔出“西南”,Oracle反省发明数据库设置的字符集为US7ASCII与客户端纷歧致,必要举行转换,但字符集ZHS16GBK中的“西南”两字在US7ASCII中没有对应的字符,以是Oracle用一致的“交换字符”拔出数据库,在这里为“?”,编码为63(00111111),这时候,输出的信息实践上已丧失,不论字符集设置怎样改动(以下面援用的实行了局),第二行SELECT出来的了局也都是两个“?”号(注重是2个,而不是4个)。

quote:
变动客户端字符集为US7ASCII
D:>SETNLS_LANG=AMERICAN_AMERICA.US7ASCII

D:>SQLPLUS"/ASSYSDBA"

没法显现用ZHS16GBK拔出的字符集,但能够显现用US7ASCII拔出的字符集
SQL>SELECT*FROMTEST;

R1
----------
西南
??


变动服务器字符集为ZHS16GBK
SQL>updateprops$setvalue$=ZHS16GBKWHERENAME=NLS_CHARACTERSET;

1rowupdated.

SQL>COMMIT;

变动客户端字符集为ZHS16GBK
D:>SETNLS_LANG=AMERICAN_AMERICA.ZHS16GBK

D:>SQLPLUS"/ASSYSDBA"

能够显现之前US7ASCII的字符集,但没法显现用ZHS16GBK拔出的数据,申明用ZHS16GBK拔出的数据为乱码。

SQL>SELECT*FROMTEST;

R1
--------------------
西南
??


必要指出的是,经由过程“updateprops$setvalue$=ZHS16GBKWHERENAME=NLS_CHARACTERSET;”来修正数据库字符集长短惯例作法,极可能引发成绩,在这里只是原文援用网友的实行了局。




实行了局剖析四

quote:
SQL>INSERTINTOTESTVALUES(西南);

1rowcreated.

SQL>SELECT*FROMTEST;

R1
--------------------
西南
??
西南

SQL>EXIT


因为此时数据库与客户真个字符集设置均为ZHS16GBK,以是不会产生字符集的转换,第一行与第三行数据显现准确,而第二行因为存储的数据就是63(00111111),以是显现的是“?”号。

quote:
变动客户端字符集为US7ASCII

D:>SETNLS_LANG=AMERICAN_AMERICA.US7ASCII

D:>SQLPLUS"/ASSYSDBA"

没法显现数据

SQL>SELECT*FROMTEST;

R1
----------
??
??
??

疑问2:第一行数据是用US7ASCII情况拔出的,为什么没法一般显现?


将客户端字符集设置改成US7ASCII落后行SELECT,Oracle反省发明数据库设置的字符集为ZHS16GBK,数据必要举行字符集转换,而第一行与第三行的汉字“东”与“北”在客户端字符集US7ASCII中没有对应字符,以是转换为“交换字符”(“?”),而第二行数据在数据库中存的原本就是两个“?”号,以是固然在客户端显现的三行都是两个“?”号,但在数据库中存储的内容倒是分歧的。

实行了局剖析五

quote:

SQL>INSERTINTOTESTVALUES(西南);

1rowcreated.

SQL>EXIT
变动客户端字符集为ZHS16GBK
D:>SETNLS_LANG=AMERICAN_AMERICA.ZHS16GBK

D:>SQLPLUS"/ASSYSDBA"

没法显现用US7ASCII拔出的字符集,但能够显现用ZHS16GBK拔出的字符集
SQL>SELECT*FROMTEST;

R1
--------------------
西南
??
西南
6+11

SQL>
疑问3:US7ASCII为ZHS16GBK的子集,为什么在US7ASCII情况下拔出的数据没法显现?

在客户端字符集设置为US7ASCII时,向字符集为ZHS16GBK的数据库中拔出“西南”,必要举行字符转换,“西南”的ZHS16GBK编码为182(10110110)、171(10101011)与177(10110001)、177(10110001),因为US7ASCII为7bit编码,Oracle将这两个汉字看成四个字符,并疏忽各字节的最高位,从而存进数据库的编码就酿成了54(00110110)、43(00101011)与49(00110001)、49(00110001),也就是“6+11”,原始信息被改动了。这时候,将客户端字符集设置为ZHS16GBK再举行SELECT,数据库中的信息不必要改动传到客户端,第1、三行因为存进的信息没有改动能显现“西南”,而第2、四行因为拔出数据时信息改动,以是不克不及显现原有信息了。



剖析了这么多的内容,但实践上总结起来也很复杂,要想在字符集方面少些毛病与贫苦,必要保持两条基础准绳:
在数据库端:选择必要的字符集(经由过程createdatabase中的CHARACTERSET与NATIONALCHARACTERSET子句指定);
在客户端:设置操纵体系实践利用的字符集(经由过程情况变量NLS_LANG设置)。


比方:
CHARACTERSETZHS16GBK
NATIONALCHARACTERSETAL16UTF16

如果你在一个遵循GPL的自由(开源)项目中使用MySQL,那么你可以遵循GPL协议使用MySQL。然而,如果你的项目不是在GPL协议下的话,你必须为使用MySQL来支付许可费用,或者你可能因为这个因素而将你的项目改为遵循GPL。
作者: 谁可相欹    时间: 2015-1-19 21:16
至于淘汰的问题,只能说在你的项目周期之内,微软应该都不会倒闭。
作者: 山那边是海    时间: 2015-1-26 22:53
你觉得我的非分区索引无法对起子分区,你可以提醒我一下呀!没有任何的提醒,直接就变成了非分区表。不知道这算不算一个bug。大家也可以试试。
作者: 仓酷云    时间: 2015-2-4 21:29
原理很简单,对要求长时间计算某一时间点的报表生成和防用户操作错误很有帮助。但是比起Oracle10g的闪回技术还是细粒度不够。可惜!
作者: 小魔女    时间: 2015-2-10 14:36
对一张百万级别的表建游标,同时又没有什么过滤条件,取得游标效率是如果直接SQL查询百万条数据;如果再对每条记录做处理,耗时将更长。
作者: admin    时间: 2015-3-1 12:47
财务软件要用SQL也只是后台的数据库而已,软件都是成品的,当然多学东西肯定是有好处的..
作者: 飘灵儿    时间: 2015-3-10 16:55
groupby子句可以将查询结果分组,并返回行的汇总信息Oracle按照groupby子句中指定的表达式的值分组查询结果。
作者: 因胸联盟    时间: 2015-3-17 08:32
呵呵,这就是偶想说的
作者: 柔情似水    时间: 2015-3-24 03:52
这就引发了对varchar和char效率讨论的老问题。到底如何分配varchar的数据,是否会出现大规模的碎片?




欢迎光临 仓酷云 (http://ckuyun.com/) Powered by Discuz! X3.2