Oracle数据库中字符串相关字段类型辨析

来源:互联网 发布:淘宝apass会员资格 编辑:程序博客网 时间:2024/06/04 23:19

本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!

1 引子

字符串类型的字段在各关系数据库中均占有重要地位。比如Oracle数据库中用于存储字符串类型数据的字段类型就超过了5种。遗憾的是,在日常工作中笔者发现很多开发者对这些类型并没有完整的认识,更不用说设计表结构时正确的选择字段类型了。本文将辨析Oracle数据库中表示字符串的各字段类型以及设计表结构时字段类型的选择依据。

2 字段类型介绍

Oracle数据库中,用于表示字符串类型的字段类型包括CHAR、VARCHAR2、VARCHAR、NCHAR、NVARCHAR2、CLOB和NCLOB等几种,下面我们来一一介绍这些类型。
2.1 CHAR
CHAR类型用于存储定长的字符串,字段长度的取值范围是1到2000字节,默认为1字节。因为CHAR是定长的,所以,当存储的字符串小于设置的字段长度时,Oracle将在字符串尾填充空格占位。比如我们定义了一个字段“TEST_CHAR CHAR(2)”,而插入的记录对应字段值为“a”,则从表中读取的记录的对应字段是填充了一个空格的“a ”。
对于CHAR类型值的比较,Oracle会在填充空格补齐到设置长度后进行。比如对于上例,当检索条件为“where TEST_CHAR=’a’”时是可以得到记录“a ”的。
另外,在定义CHAR的长度时可以使用单位名称BYTE或CHAR,默认为BYTE。即“TEST_CHAR CHAR(2 BYTE)”意为长度为2个字节的CHAR,而“TEST_CHAR CHAR(2 CHAR)”意为长度为2个字符的CHAR。
这里说的“字节”是存储字段信息所占用的物理存储空间,而“字符”则是指存储的信息的最小逻辑单位。当数据库使用单字节字符集时,一个字符的存储空间就是一个字节,而当数据库使用多字节字符集时,一个字符的存储空间可能是1到n个字节。
2.2 VARCHAR2
VARCHAR2类型用于存储变长的字符串,字段长度的取值范围是1到4000字节。VARCHAR2是变长的,这意味着实际存储长度与具体的字符串有关。
对于VARCHAR2类型的比较,Oracle不会预先填充空格,而是直接比较值。比如我们定义一个字段“TEST_VARCHAR2 VARCHAR2(2)”,插入对应字段值为“a ”的记录。当检索条件为“where TEST_ VARCHAR2=’a’”时是无法得到记录“a ”的。
另外,与CHAR一样,在定义VARCHAR2类型字段的最大长度时可以使用单位名称BYTE或CHAR,默认为BYTE。即“TEST_ VARCHAR2 VARCHAR2(2 BYTE)”意为最大长度为2个字节的VARCHAR2,而“TEST_ VARCHAR2 VARCHAR2 (2 CHAR)”意为长度为2个字符的VARCHAR2。
2.3 VARCHAR
在Oracle中,VARCHAR被定义为VARCHAR2的别名,其一切行为、特征与VARCHAR2相同。据传,起初,Oracle预留了VARCHAR字段类型用于与其他数据库兼容。而时至今日,它仍作为VARCHAR2的别名存在,其意义恐怕只是对Oracle数据库自身的向下兼容了。
2.4 NCHAR
NCHAR类型用于存储定长的Unicode字符串,其字符集只能是AL16UTF16或UTF8,与数据库安装时指定的字符集相同。有关Oracle数据库字符集的相关知识可参见Oracle官网在线文档Database Globalization Support Guide( https://docs.oracle.com/database/121/NLSPG/applocaledata.htm#NLSPG014)。
在设置NCHAR类型字段的长度时,不支持设置单位名称,即单位名称均为“字符”。比如“TEST_NCHAR NCHAR(2)”指长度为2个字符的NCHAR类型字段。NCHAR字段的最大长度是2000个字节。这意味着它最多可以存储2000个字符,但这些字符的实际存储空间不能超过2000个字节。
NCHAR的其他特性与CHAR相同,恕不赘述。
2.5 NVARCHAR2
NVARCHAR2类型用于存储变长的Unicode字符串,其特性参见VARCHAR2和NCHAR,恕不赘述。
2.6 CLOB
CLOB类型用于存储最大不超过128TB的变长字符串。CLOB支持事务,但不支持跨事务和会话的定位。下面的示例定义了一个叫做CLOB_TEST的CLOB类型的字段:CLOB_TEST CLOB。
因为CLOB类型的字段在表中记录的是实际信息的指针,因此无法在sql语句中使用比较运算符。如果我们需要查找CLOB_TEST值为“a”的记录可以使用查询条件“where dbms_lob.compare(t.clob_test,’a’)=0”。
2.7 NCLOB
NCLOB类型用于存储最大不超过128TB的Unicode变长字符串。NCLOB的其他特性与CLOB相同,恕不赘述。

3 字段类型选择依据

既然Oracle数据库提供了多种字段类型用于字符串类型数据的存储,那么我们在设计数据库表结构时应该如何选择呢?笔者认为应该从各字段类型的区别、限制入手,抓住字符串类型数据的关键特性,从而选择出最适合的字段类型。下面将逐一介绍这些关键特性。
3.1 最大长度
从存储信息的角度来说,字段支持的字符串长度是信息能否被完整保留的重要条件。CHAR和NCHAR的最大长度是2000字节,VARCHAR2和NVARCHAR2的最大长度是4000字节,CLOB和NCLOB的最大长度是128TB。当我们要选择一个字段类型来存储字符串信息时,应当首先根据业务模型判断字符串的最大值,排除掉无法满足最大存储需求的字段类型。因为CLOB(NCLOB)类型使用时的诸多不便,当CHAR(NCHAR)和VARCHAR2(NVARCHAR)字段类型的最大长度限制可以满足业务需求时,通常不使用CLOB(NCLOB)类型。
3.2 是否定长
CHAR(NCHAR)类型与VARCHAR2(NVARCHAR2)类型最大的区别在于是否定长。CHAR(NCHAR)类型是定长的,这意味着它拥有更高的访问效率。但是,当实际存储的信息小于设置的字段长度时,Oracle会用空格来填充,此时会浪费一定的存储空间。虽然对于单条记录这个影响可以忽略不计,但对于海量记录,这个浪费就需要引起足够的重视了。
VARCHAR2(NVARCHAR2)的情形与CHAR(NCHAR)刚好相反。它通过牺牲访问效率获得了更高的空间利用率。
3.3 存储内容包含的字符
NCHAR、NVARCHAR2、NCLOB类型存储Unicode字符串,仅支持AL16UTF16或UTF8字符集。虽然实际工作中很少遇到,但如果要存储的字符超出AL16UTF16和UTF8字符集范围,那就无法使用NCHAR、NVARCHAR2、NCLOB等字段类型了。
3.4 是否需要建立索引
如果需要为存储字符串的字段建立索引,那么我们要格外注意其对字段类型的限制。在CLOB和NCLOB类型的字段上是不能建立普通索引的。而在NCLOB类型的字段上是不能建立文本索引(如CONTEXT)的。
3.5 是否可能出现数据库迁移
如果可以预见在将来数据库可能发生迁移,那么设计数据库表结构时应该充分考虑字段类型的兼容性。比如,将Oracle中的NCHAR类型迁移到IBM DB2时,就需要通过CCSID子句创建兼容Unicode字符集的CHAR或VARCHAR。

4 常见场景的字段类型选择

第3节中从技术角度讨论了存储字符串类型数据时的选择依据,属于设计表结构时的一些指导原则。本节将以工作指导书的形式介绍在工作中经常涉及的几个业务场景中的字段类型选择及原因,帮助读者更深刻的理解各字段类型的差异。
4.1 记录状态及可枚举值
在数据库设计中,我们常常需要表示记录状态的字段。比如,用“R”表示记录已发布,“O”表示记录被检出;再比如用“O”表示树节点已展开,用“C”表示树节点已关闭;甚至表示布尔,用“1”表示真,用“0”表示假。
这类场景存储的字符串具有定长(或最大长度可知)、可枚举、信息通常为英文字母或数字、经常作为检索过滤条件等特点。
对于这类场景,我们通常使用CHAR类型字段进行存储。
4.2 GUID、UUID与MD5
GUID和UUID是我们经常使用的全局唯一标识符。它们具有长度、格式统一,字符可枚举(16进制数字)的特点。相应的,用于校验的MD5、SH-11、CRC等也有类似的特征。
对于这类字符串,我们通常使用CHAR类型字段来存储。
4.3 单据号、证件号
业务系统中经常需要存储符合一定格式的单据号、证件号。它们除了具有定长、字符可枚举的特点外,还是一些信息的编码集合。以身份证为例,18位数字中就包含了户籍地址、出生日期、性别、校验码等信息。因此,它们通常会被用于创建文本索引或函数索引。
对于单据号、证件号类型的字符串,我们通常使用CHAR类型字段来存储。
4.4 普通字符串
对于诸如“产品型号”、“产品规格”等一般业务属性字符串,通常符合变长、长度不超过4000字节的特征。
因此,我们可以使用VARCHAR2来存储这个类型的字符串。
4.5 静态页面、大文本
在一些web项目中,我们会将静态页面文件存储在数据库表中。一些基于诸如FreeMarker等模版引擎的项目也会将模版文件存储于数据库表中。另外,一些类似论坛、博客、新闻功能的应用也存在存储大量字符串的需求。
对于以上类型的需求,用排除法可知,能够几乎不受长度限制进行大文本存储的类型只有CLOB和NCLOB。当然,依前所述,我更倾向于使用CLOB。

0 0