字符型字段是数据库表中最常见的字段,而字符型字段又分为定长和变长两种。一般来说,VARCHAR类型用于存储内容长度变化较大的数据,CHAR类型用于存储内容长度没有变化或变化不大的数据。
在数据的内部存储上,一般VARCHAR型字段会使用1或2个字节作为数据的长度描述,数据的后面不含无意义的空格;而CHAR型字段会将数据的结尾以空格填充,直至填满定义的长度。
在数据的操作效率上,UPDATE含有变长字段的变长记录会花费较多时间,而对INSERT、DELETE和SELECT操作则没有明显差别。
在数据的索引和匹配上,VARCHAR型字段会将’张三’和’张三 ‘认为是两项不同的数据,而CHAR则认为它们是等同的。
当CHAR型字段与VARCHAR型字段进行关联时,多数的数据库都是以变长字段作为基准,不对CHAR型字段的尾部空格进行裁剪。因此,VARCHAR(12)中的’张三’和CHAR(12)中的’张三’是不相等的,无法进行直接关联。
通常,对于VARCHAR型字段的处理周期为:获取数据、TRIM数据、存储数据、读取数据、展示数据;而对于CHAR型字段的处理周期为:获取数据、存储数据、读取数据、TRIM数据、展示数据。
从对比中我们可以看出,两者的差别在于TRIM数据的处理位置。实际上两者差别还在于:对于VARCHAR型字段来说,TRIM是必须的,而对于CHAR型字段来说,TRIM则是根据需要可选的。也就是说,总体上讲,VARCHAR型字段的处理过程比CHAR型字段的处理过程复杂,因而效率也就不如CHAR型字段高。
另一方面,在进行字段值相等的判断时,VARCHAR型字段首先比较两个字段值的长度,只有在长度相同的情况下才进一步比较其内容;而CHAR型字段直接进行内容的比较。因此从字段值相等的判断这个角度来看,多数情况下,VARCHAR型字段的效率要高于CHAR型字段。
那么在数据库表的设计时,应该如何选择字段的CHAR和VARCHAR类型呢?我主张的原则是:对于长度变化不大的字段,应该使用CHAR型,而对于长度变化较大的字段,则可以考虑使用VARCHAR。还有一些长度变化较大的字段,由于其记录经常被修改,为提高效率,这类字段也应该使用CHAR型字段。也就是说,应该首选CHAR型。举几个例子来说明:
对于9位的机构编码字段,由于所有编码都是9位填满的,因此应该使用CHAR型,如果使用了VARCHAR型,则不仅浪费了存储空间,也降低了所有处理的效率。
对于身份证号码,由于存在15位与18位的差别,此时可以选择使用VARCHAR字段;但是考虑到15和18之间的变化不大,使用CHAR字段也是可以的。特别是15位身份证号是一个历史遗留问题,后续的数据都将是18位的,因此选用CHAR型字段对将来的效率优势是明显的。
对于家庭住址,由于其长度的差距会较大,而且其所在记录也不会被频繁修改,因此非常适宜用VARCHAR型字段进行存储。
通常情况下,满足下列条件之一,我们就应该使用CHAR:
1.字段值长度不变或变化不大;
2.所在记录会被频繁修改。
掌握了上述原则,我们就可以在数据库表的设计时,通过综合考虑各方面的因素来确定字符型数据的类型。按照上一篇中推荐的“业务键”设计模式,通常作为主键的字段都是长度没有变化或变化不大的字段,如账号、卡号、机构号、身份证号等,应该采用CHAR型;而对于其它非索引字段,可根据其内容及其它因素选用CHAR或VARCHAR。
当我们的数据表与外部系统的数据表关联时,如果对方没有按照我们的规则进行数据库表设计,导致在关联字段上一方使用的是CHAR而另一方为VARCHAR,这时就要仔细斟酌数据的转换方式。
如果双方在关联字段上都没有索引,则将CHAR转为VARCHAR会好一些;如果一方有索引而另一方没有,那么就要把关联的数据类型转换为有索引的那个;如果双方都有索引且都要在操作中使用,那么就将数据记录相对较少的那个转换为相对较多的那个。CHAR转VARCHAR使用TRIM,VARCHAR转CHAR使用CAST。
现在,VARCHAR的滥用是数据库设计中另一个非常严重的现象。在数据库设计时,不对数据进行调研和分析,甚至直接想当然地就把所有字符字段设定为VARCHAR(30),这对应用系统的运行和维护都是非常不利的。不针对字段的特点进行精确的描述,就不便于精确地理解业务模型,随着应用系统功能的不断扩充和升级,整个系统模型就会越来越模糊,直至无法维护,最后只好推翻重来,这个代价是非常大的。