2008年11月19日星期三

ORACLE里的char,varchar2,nchar,nvarchar2讨论

转自ITPUB,原文请看这里。

这篇文章对这几种数据类型的讨论非常清楚,另外还推荐看看TOM的大作,ORACLE9i&10g编程艺术--深入数据库体系结构,一书的关于数据类型的那一章。

今天上午和杨老大讨论了一下char,varchar2,nchar,nvarchar2几种字符类型,发现有几种类型不大容易
分的清除,于是做了一下试验,希望能够对大家有所帮助。(高手请跳过)
如果你也搞不太清楚这几种类型,下面的东东可能对你有所帮助。
首先介绍一下环境,字符集是ZHS16GBK,国家字符集是Al16UTF16
第一步:建一张表:
SQL> create table typetest(cha char(10),varcha varchar2(10),ncha nchar(10),nvarcha
nvarchar2(10));
表已创建。
第二步:插入一行:
SQL> insert into typetest values('a','a','a','a');
已创建 1 行。
SQL> commit;
提交完成。
然后用DUMP查看一下库中的实际存储的内容:
SQL> select dump(cha),dump(varcha),dump(ncha),dump(nvarcha) from typetest;
DUMP(CHA)
--------------------------------------------------------------------------------
DUMP(VARCHA)
--------------------------------------------------------------------------------
DUMP(NCHA)
--------------------------------------------------------------------------------
DUMP(NVARCHA)
--------------------------------------------------------------------------------
Typ=96 Len=10: 97,32,32,32,32,32,32,32,32,32
Typ=1 Len=1: 97
Typ=96 Len=20: 0,97,0,32,0,32,0,32,0,32,0,32,0,32,0,32,0,32,0,32
Typ=1 Len=2: 0,97
发现了什么?没发现什么?滚一边去
这样我们得出了结论1:
char nchar 类型是按照定义的长度存储数据的,如果数据不够,后面补空格
varchar nvarchar2 是变长数据类型,实际长度随着存放的数据量改变
进一步思考,可以得出以下结论,用char就是空间换时间,用varchar2就是时间换空间,因为char占用较多
的空间,但是因为规则,处理起来会比较快,varchar2比较节省空间,但是处理起来比较慢,而且如果频
繁的做UPDATE还会产生行转移,会造成数据库性能下降。(什么叫行转移?你真的想知道?有空的时候来
找我,我慢慢将给你听)
接着做试验:

SQL> insert into typetest values('我','我','我','我');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select dump(cha),dump(varcha),dump(ncha),dump(nvarcha) from typetest;
DUMP(CHA)
--------------------------------------------------------------------------------
DUMP(VARCHA)
--------------------------------------------------------------------------------
DUMP(NCHA)
--------------------------------------------------------------------------------
DUMP(NVARCHA)
--------------------------------------------------------------------------------
Typ=96 Len=10: 206,210,32,32,32,32,32,32,32,32
Typ=1 Len=2: 206,210
Typ=96 Len=20: 98,17,0,32,0,32,0,32,0,32,0,32,0,32,0,32,0,32,0,32
Typ=1 Len=2: 98,17
可以看到char和varhcar是用的GBK编码的,nchar和nvarchar2是用的utf16,国家字符集进行编码的
继续向下看
SQL> insert into typetest values('我我我我我','我我我我我','我我我我我','我我我我我');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select dump(cha),dump(varcha),dump(ncha),dump(nvarcha) from typetest;


DUMP(CHA)
--------------------------------------------------------------------------------
DUMP(VARCHA)
--------------------------------------------------------------------------------
DUMP(NCHA)
--------------------------------------------------------------------------------
DUMP(NVARCHA)
--------------------------------------------------------------------------------
Typ=96 Len=10: 206,210,206,210,206,210,206,210,206,210
Typ=1 Len=10: 206,210,206,210,206,210,206,210,206,210
Typ=96 Len=20: 98,17,98,17,98,17,98,17,98,17,0,32,0,32,0,32,0,32,0,32
Typ=1 Len=10: 98,17,98,17,98,17,98,17,98,17

SQL> insert into typetest values('我我我我我我','我我我我我','我我我我我','我我我我我');
insert into typetest values('我我我我我我','我我我我我','我我我我我','我我我我我')
*
第 1 行出现错误:
ORA-12899: 列 "COMM"."TYPETEST"."CHA" 的值太大 (实际值: 12, 最大值: 10)

SQL> insert into typetest values('我我我我我','我我我我我','我我我我我我我我我我','我我我我
我我我我我我');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select dump(cha),dump(varcha),dump(ncha),dump(nvarcha) from typetest;

DUMP(CHA)
--------------------------------------------------------------------------------
DUMP(VARCHA)
--------------------------------------------------------------------------------
DUMP(NCHA)
--------------------------------------------------------------------------------
DUMP(NVARCHA)
--------------------------------------------------------------------------------
Typ=96 Len=10: 206,210,206,210,206,210,206,210,206,210
Typ=1 Len=10: 206,210,206,210,206,210,206,210,206,210
Typ=96 Len=20: 98,17,98,17,98,17,98,17,98,17,98,17,98,17,98,17,98,17,98,17
Typ=1 Len=20: 98,17,98,17,98,17,98,17,98,17,98,17,98,17,98,17,98,17,98,17
OK,看出结论没,char和varchar是通过数据实际占用的比特数计算长度的,nchar和nvarchar是实际能够存
放的字数为计算长度的,如果是al16utf16,那它可以存放10个汉字,那么实际占用的比特数就是20。
(可以想一想如果用UTF8做为国家字符集会产生什么样的结果)
最后讲一下,测字符串长度
你能告诉我length('我我我我我')的值是多少吗?lengthb('我我我我我')呢?lengthc('我我我我我')呢

给大家看一下结果,看看你猜的对不对
SQL> select * from typetest;
CHA VARCHA NCHA NVARCHA
---------- ---------- -------------------- --------------------
a a a a
我 我 我 我
我我我我我 我我我我我 我我我我我 我我我我我
我我我我我 我我我我我 我我我我我我我我我我 我我我我我我我我我我

SQL> select length(cha),length(varcha),length(ncha),length(nvarcha) from typetest;
LENGTH(CHA) LENGTH(VARCHA) LENGTH(NCHA) LENGTH(NVARCHA)
----------- -------------- ------------ ---------------
10 1 10 1
9 1 10 1
5 5 10 5
5 5 10 10
SQL> select lengthb(cha),length(varcha),length(ncha),length(nvarcha) from typetest;
LENGTHB(CHA) LENGTH(VARCHA) LENGTH(NCHA) LENGTH(NVARCHA)
------------ -------------- ------------ ---------------
10 1 10 1
10 1 10 1
10 5 10 5
10 5 10 10

SQL> select lengthc(cha),lengthc(varcha),lengthc(ncha),lengthc(nvarcha) from typetest;
LENGTHC(CHA) LENGTHC(VARCHA) LENGTHC(NCHA) LENGTHC(NVARCHA)
------------ --------------- ------------- ----------------
10 1 10 1
9 1 10 1
5 5 10 5
5 5 10 10
有问题欢迎和我讨论!

没有评论: