oracle⾥⾯char类型,Oracle11g中的char类型使⽤
在Oracle数据表和程序类型中,字符类型可能是使⽤最多的⼀种了。从历史上看,Oracle⾸先推出了固定长度char类型字段,之后才推出了变长度类型varchar2。⽬前,主流Oracle应⽤开发都已经普遍接受了varchar2作为数据表字段类型表⽰。如果存在超长字符,都考虑使⽤CLOB这类⼤对象进⾏存储。
但是,我们在实际领域中,还是会在各种遗留系统中发现很多char类型字段。⽽且连带这些遗留系统的下游系统中,char类型也会经常出现。在这样的背景下,开发运维⼈员其实还是有很多的接触char的机会的。
Char最⼤的特点就是固定长度存储,例如定义长度char(10),保存的字符串为’kkk’三位长度。在保存的时候,Oracle会⾃动将其尾部补齐空格。这样就确保了每个保存在char(10)的字段都是10位长度。根据笔者的猜测,char的策略是在Oracle对于存储空间管理能⼒较弱的背景下提出的⼀种折中策略。随后,varchar2的出现逐步将这种变通策略加以替代。
在⼀些时候,笔者还是会遇到⼀些朋友的问题:明明检索全表时候看到字符串取值是xxx,但是⽤SQL加在后⾯where条件的时候,就没有检索结果,仿佛“见⿁⼀样”。究其根源,常常是char在⾥⾯“捣乱”,where条件后⾯加上若⼲个空格或者使⽤rpad命令进⾏补全。
本篇主要介绍⼏个在11g⾥⾯常见的使⽤场景。注意:随着版本的升级,Oracle对于char的⽀持其实也在不断升级(默默地),尽可能让其靠近varchar2的使⽤效果。所以,本⽂中的实验内容,在其他版本下可能会有不同的测试结果,请注意。
1、环境说明
本⽂使⽤Oracle 11gR2进⾏测试,具体版本为11.2.0.4。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0    Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 – Production
创建实验数据表T。
SQL> create table t (chr_a char(100), vchar_a varchar2(100));
Table created
SQL> desc t;
Name    Type          Nullable Default Comments
------- ------------- -------- ------- --------
CHR_A  CHAR(100)    Y
VCHAR_A VARCHAR2(100) Y
SQL> insert into t select owner, owner from dba_objects;
119498 rows inserted
SQL> commit;
Commit complete
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
数据取值’SCOTT’的记录数⽬为6。
SQL> select count(*) from t where vchar_a='SCOTT';
COUNT(*)
----------
6
2、常量where条件测试
⾸先我们测试⼀下单独写常量条件的情况。
SQL> select count(*) from t where chr_a='SCOTT';
COUNT(*)
----------
6
SQL> select length(chr_a) from t where chr_a='SCOTT';
LENGTH(CHR_A)
-------------
100
100
100
100
100
100
linux系统安装oracle11g6 rows selected
上⾯两个SQL语句表明:在使⽤常量作为条件的where语句时候,即使字段类型是char,系统会⾃动进⾏右侧空格的“补齐”动作,让其满⾜char条件,检索出正确的结果。借助length函数,我们也可以确定长度为100。
笔者⼀直想了解这个“偷天换⽇”的过程,从执⾏计划⾓度也不能看出实际的情况。
SQL> explain plan for select count(*) from t where chr_a='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display(format => 'advanced'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |  101 |  510  (1)| 00:00:07 |
|  1 |  SORT AGGREGATE    |      |    1 |  101 |            |          |
|*  2 |  TABLE ACCESS FULL| T    |    11 |  1111 |  510  (1)| 00:00:07 |
---------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / T@SEL$1
Outline Data
-------------
/*+
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
BEGIN_OUTLINE_DATA
FULL(@"SEL$1" "T"@"SEL$1")
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
DB_VERSION('11.2.0.4')
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("CHR_A"='SCOTT')
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - (#keys=0) COUNT(*)[22]
39 rows selected
从执⾏计划上,我们看不出什么过多的端倪。filter条件中也没有对chr_a取值进⾏格外的处理。这个过程其实是针对char类型进⾏的特殊处理,如果我们在where条件后⾯⼈为加上空格,会如何呢?
SQL> select count(*) from t where chr_a='SCOTT ';
COUNT(*)
----------
6
SQL> select count(*) from t where chr_a='SCOTT    ';
COUNT(*)
----------
6
同样可以正确到结果。对应执⾏计划为:
SQL> explain plan for select count(*) from t where chr_a='SCOTT    '; Explained
SQL> select * from table(dbms_xplan.display(format => 'advanced')); PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time    | ---------------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |  101 |  510  (1)| 00:00:07 |
|  1 |  SORT AGGREGATE    |      |    1 |  101 |            |          |
|*  2 |  TABLE ACCESS FULL| T    |    11 |  1111 |  510  (1)| 00:00:07 | ---------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / T@SEL$1
Outline Data
-------------
/*+
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
BEGIN_OUTLINE_DATA
FULL(@"SEL$1" "T"@"SEL$1")
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
DB_VERSION('11.2.0.4')
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("CHR_A"='SCOTT    ')
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - (#keys=0) COUNT(*)[22]
39 rows selected
执⾏计划上同样看不到什么变化。
上⾯的实验,告诉我们char常量使⽤规则:如果在where条件后⾯使⽤常量取值,Oracle会根据字段类型和常量情况进⾏⾃动补齐空格动作。常量后⾯⼈为添加的空格也会作为⾃动空格加以处理。
下⾯讨论如果是rpad函数在常量上,效果如何呢?
3、函数操作效果
在⼀些⽐较⽼的版本Oracle版本⾥⾯,⼀些开发⼈员为了避免char空格影响,⼴泛使⽤了rpad函数,⾃动的添加后⾯的空格。
SQL> select count(*) from t where chr_a=rpad('SCOTT',100,' ');
COUNT(*)
----------
6
正常是可以到结果的。执⾏计划上,filter部分显然是先计算出函数取值,之后再进⾏处理。
SQL> explain plan for select count(*) from t where chr_a=rpad('SCOTT',100,' ');
Explained
SQL> select * from table(dbms_xplan.display(format => 'advanced'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
(篇幅原因,有省略……)
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("CHR_A"='SCOTT
')
Column Projection Information (identified by operation id):

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。