Oracle中CHAR与VARCHAR2的区别

CHAR与VARCHAR2都是Oracle的数据存储格式。CHAR是定长的,VARCHAR2是变长。都可以存储字符串。

      需要注意的是使用CHAR的时候。Select查询要注意定长的格式。查询字符串的长度要刚好。多了少了都不能查不到数据。例如字段A为CHAR(10)。存“abcdefg”,长度不满10。Oracle会用空格补满10位。你用"abcefg"作为查询字段时是查不出来的。这就是我花了一个下午调程序。总以为是程序写错了。到最后发现建表的人对这表用的是CHAR,而其他的表用的是VARCHAR2。我完败于细节。


char是定长的 char(10)   varchar2(10)  同样存 a ,char占用了10个字符,varchar2 只占用了 一个字符(一个中文占两个字符,英文占一个)。 
但是char的查询速度要比varchar2快。varchar2,Oracle还要进行语法分析,这个字段是多少位的,所以慢一些。相对于上千万的记录来说。

一般的项目 没什么区别,随便用


区别:   1.CHAR的长度是固定的,而VARCHAR2的长度是可以变化的, 比如,存储字符串“abc",对于CHAR (20),表示你存储的字符将占20个字节(包括17个空字符),而同样的VARCHAR2 (20)则只占用3个字节的长度,20只是最大值,当你存储的字符小于20时,按实际长度存储。   2.CHAR的效率比VARCHAR2的效率稍高。   3.目前VARCHAR是VARCHAR2的同义词。工业标准的VARCHAR类型可以存储空字符串,但是oracle不这样做,尽管它保留以后这样做的权利。Oracle自己开发了一个数据类型VARCHAR2,这个类型不是一个标准的VARCHAR,它将在数据库中varchar列可以存储空字符串的特性改为存储NULL值。如果你想有向后兼容的能力,Oracle建议使用VARCHAR2而不是VARCHAR。   何时该用CHAR,何时该用varchar2?   CHAR与VARCHAR2是一对矛盾的统一体,两者是互补的关系.   VARCHAR2比CHAR节省空间,在效率上比CHAR会稍微差一些,即要想获得效率,就必须牺牲一定的空间,这也就是我们在数据库设计上常说的‘以空间换效率’。   VARCHAR2虽然比CHAR节省空间,但是如果一个VARCHAR2列经常被修改,而且每次被修改的数据的长度不同,这会引起‘行迁移’(Row Migration)现象,而这造成多余的I/O,是数据库设计和调整中要尽力避免的,在这种情况下用CHAR代替VARCHAR2会更好一些。


char和Varchar2在Oracle的内部存储格式都一样都是数据长度length+实际数据data,其中数据长度length用1-3个字节表示,length<255字节的使用1个字节,length>255用3个字节表示。

Thomas Kyte的建议是忘记有char类型的存在,在一切需要字符的地方都是用varchar2格式。

不过,如果混合使用并匹配 VARCHAR2 和 CHAR ,你就会不断地遭遇这个问题。不仅如此,开发人员 现 
在还必须在应用中考虑字段宽度。如果开发人员喜欢使用 RPAD() 技巧将绑定变量转换为某种能与 CHAR 字 
段比较的类型(当然,与截断( TRIM )数据库列相比,填充绑定变量的做法更好一些,因为对列应用函数 
TRIM 很容易导致无法使用该列上现有的索引),可能必须考虑到经过一段时间后列长度的变化。如果字段 
的大小有变化,应用就会受到影响,因为它必须修改字段宽度。 
正是由于以下这些原因:定宽的存储空间可能导致表和相关索引比平常大出许多,还伴随着绑定变 量 
问题,所以无论什么场合我都会避免使用 CHAR 类型。即便是对单字符的字段,我也想不出有什么必要使 用 
CHAR 类型,因为在这种情况下,这两种类型确实没有显著差异。 VARCHAR2(1) 和 CHAR(1) 从任何方面来讲 都 
完全相同。此时,使用 CHAR 类型并没有什么有说服力的理由,为了避免混淆,所以我 “ 一律排斥 “ ,即 使 
是 CHAR(1) 字段(即单字符字段)也不建议使用 CHAR 类型。

下面链接是AskTom中关于char和Varchar2的区别的讨论:

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:123212348063

 

经常有人说,char的性能比varchar的性能好,做下试验测试:

create table test (key number , char_str char(50),varchar_str varchar2(50));

insert into test select rownum,object_id,object_id from dba_objects;

insert into test select rownum+50530 ,object_id+50530,object_id+50530 from dba_objects;

insert into test select rownum+150530 ,object_id+150530,object_id+150530 from dba_objects;

commit;

select count(*) from test;

COUNT(*) 
--------- 
   151560

set autotr on exp

select * from test where char_str='asjdfa';

no rows selected

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 1357081020

-------------------------------------------------------------------------- 
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     | 
-------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT  |      |    16 |  1472 |   328   (4)| 00:00:04 | 
|*  1 |  TABLE ACCESS FULL| TEST |    16 |  1472 |   328   (4)| 00:00:04 | 
--------------------------------------------------------------------------

Predicate Information (identified by operation id): 
---------------------------------------------------

   1 - filter("CHAR_STR"='asjdfa')

Note 
----- 
   - dynamic sampling used for this statement

select * from test where varchar_str='asjdfa';

no rows selected

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 1357081020

-------------------------------------------------------------------------- 
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     | 
-------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT  |      |    16 |  1472 |   324   (3)| 00:00:04 | 
|*  1 |  TABLE ACCESS FULL| TEST |    16 |  1472 |   324   (3)| 00:00:04 | 
--------------------------------------------------------------------------

Predicate Information (identified by operation id): 
---------------------------------------------------

   1 - filter("VARCHAR_STR"='asjdfa')

Note 
----- 
   - dynamic sampling used for this statement

结论:同一个条件varchar2和char的性能基本一样;

在char_str和varchar_str上分别建索引后的查看查询效率;

create index char_idx on test(char_str);

create index varchar_idx on test(varchar_str);

select * from test where char_str='20';

       KEY CHAR_STR                                                                                     VARCHA 
---------- --------------------------------------------------------------------------------------------------- 
-------------------------------------------------------------- 
         1 20                                                                                               20

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 4119847653

---------------------------------------------------------------------------------------- 
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     | 
---------------------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT            |          |     1 |    92 |     4   (0)| 00:00:01 | 
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |     1 |    92 |     4   (0)| 00:00:01 | 
|*  2 |   INDEX RANGE SCAN          | CHAR_IDX |     1 |       |     3   (0)| 00:00:01 | 
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id): 
---------------------------------------------------

   2 - access("CHAR_STR"='20')

Note 
----- 
   - dynamic sampling used for this statement

select * from test where varchar_str='20';

       KEY CHAR_STR                                                                                     VARCHAR_STR 
---------- ---------------------------------------------------------------------------------------------------- ------------- 
-------------------------------------------------------------- 
         1 20                                                                                               20

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2912297006

------------------------------------------------------------------------------------------- 
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     | 
------------------------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT            |             |     1 |    92 |     2   (0)| 00:00:01 | 
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST        |     1 |    92 |     2   (0)| 00:00:01 | 
|*  2 |   INDEX RANGE SCAN          | VARCHAR_IDX |     1 |       |     1   (0)| 00:00:01 | 
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id): 
---------------------------------------------------

   2 - access("VARCHAR_STR"='20')

Note 
----- 
   - dynamic sampling used for this statement

结论:在对于字段有索引的情况下,其select效率是一样的,甚至varchar2还表现的效率高点。

再来查看下同样的数据char和varchar2空间利用的比较;

SQL> select sum(bytes/1024/1024) as char_idx_used_mb  from user_segments where segment_name='CHAR_IDX';

CHAR_IDX_USED_MB 
---------------- 
              11

SQL> select sum(bytes/1024/1024) as char_idx_used_mb  from user_segments where segment_name='VARCHAR_IDX';

CHAR_IDX_USED_MB 
---------------- 
               3

同样的数据char 索引比varchar索引的使用空间要大将近3倍,也就说同样的数据在表中char列的存储空间比varchar2的存储空间大将近3倍左右;当然这个比例跟存入表中char和varchar2列中的数据有关,如果存入char列中数据接近其定义的长度,那么char与varchar2的存储空间将差不多。


  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值