数据类型的比较
char表示的是固定长度,最长n个字
varchar表示的是实际长度的数据类型
比如:如果是char类型,当你输入字符小于长度时,后补空格;而是varchar类型时,则表示你输入字符的实际长度
(n为某一整数,不同数据库,最大长度n不同)

CHAR:CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间。

VARCHAR:存储变长数据,但存储效率没有CHAR高,如果一个字段可能的值是不固定长度的,我们只知道它不可能超过10个字符,把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。为什么"+1"呢?这一个字节用于保存实际使用了多大的长度。从空间上考虑,用varchar合适;从效率上考虑,用char合适,关键是根据实际情况找到权衡点。

char和varchar区别:

varchar比char节省空间,但在效率上比char稍微差一些。

说varchar比char节省空间,是因为varchar是可变字符串,比如:用varchar(5)存储字符串“abc”,只占用3个字节的存储空间,而用char(5)存储,则占用5个字节(“abc  ”)。
说varchar比char效率稍差,是因为,当修改varchar数据时,可能因为数据长度不同,导致数据迁移(即:多余I/O)。其中,oracle对此多余I/O描述的表达是:“行迁移”(Row Migration)。

“行迁移”(Row Migration):

 “当一行的记录初始插入时是可以存储在一个block中的,由于更新操作导致行增加了,而block的自由空间已经完全满了,这个时候就产生了行迁移。在这种情况下,oracle将会把整行数据迁移到一个新的block中,oracle会保留被迁移的行的原始指针指向新的存放行数据的block,这就意味着被迁移行的ROW ID是不会改变的。"

其中要解释一下:block是oracle中最小的数据组织与管理单位,是数据文件磁盘储存空间单位,也是数据库I/O最小单位(也就是说,读和写都是一个block打大小,所以如果block没满时,更新内容长度变更的varchar字段,和更新内容长度没变的varchar字段,I/O次数是一样,不存在额外消耗,只有在block满时,才会出现额外I/O,所以char和varchar性能之间的性能差异,是相当细微的,绝大多数情况下可以忽略不计,所以上文描述的“稍”差的含义)

nvarchar
  (需要注意,mysql中由于使用了utf-8,所以无论汉字还是字母,都是一个长度的char,所以就不用分nvarhcar和varchar了,一律作varchar)
     nvarchar的特性,需要和varchar对比。

     nvarchar和varchar的不同主要是在对于数据的存储方式上:
1). varchar:按字节存储数据
varchar(6),最多能存储6个字节的数据,比如:“哈哈哈”,“abcdef”......
备注:一个中文字符在数据库里占多少个字节,要看unicode的编码方式,比如:utf8在mysql上占3个字节,sqlserver的Chinese_PRC_CI_AS占2个字节...
2). nvarchar:按字符存储数据
nvarchar(6),最多能存储6个字符/中文数据,比如:"哈哈哈哈哈哈",“abcdef”......
nvarchar(m)最大存储的实际字节长度=n*m(n跟据编码方式而定),如果nvarchar存储的是英文字符,也是根据编码方式存储n的字节长度。也就是说,如果用nvarchar存储英文字符,会浪费一半以上的存储空间....

 一、VARCHAR与CHAR字符型数据的差异

  在MySQL数据库中,用的最多的字符型数据类型就是Varchar和Char。

  这两种数据类型虽然都是用来存放字符型数据,但是无论从结构还是从数据的保存方式来看,两者相差很大。而且其具体的实现方式,还依赖与存储引擎

  这里就以大家最常用的MYISAM存储引擎为例,谈谈这两种数据类型的差异。在后续建议中,也是针对这种存储类型而言的。

  这里首先需要明白的一点是,这两种数据类型,无论采用哪一种存储引起,系统存储数据的方式都是不同的。正是因为如此,才有必要研究两者的不同。然后在合适的情况下,采用恰当的方式。了解这一点之后,再来看后续的内容。  

Varchar往往用来保存可变长度的字符串。

  简单的说,我们只是给其固定了一个最大值,然后系统会根据实际存储的数据量来分配合适的存储空间。为此相比CHAR字符数据而言,其能够比固定长度类型占用更少的存储空间。不过在实际工作中,由于某系特殊的原因,会在这里设置例外。如管理员可以根据需要指定ROW_FORMAT=FIXED选项。利用这个选项来创建MyISAM表的话,系统将会为每一行使用固定长度的空间。此时会造成存储空间的损耗。通常情况下,VARCHAR数据类型能够节约磁盘空间,为此往往认为其能够提升数据库的性能。

  不过这里需要注意的是,这往往是一把双刃剑。其在提升性能的同时,往往也会产生一些副作用。如因为其长度是可变的,为此在数据进行更新时可能会导致一些额外的工作。如在更改前,其字符长度是10位(Varchar规定的最长字符数假设是50位),此时系统就只给其分配10个存储的位置(假设不考虑系统自身的开销)。更改后,其数据量达到了20位。由于没有超过最大50位的限制,为此数据库还是允许其存储的。只是其原先的存储位置已经无法满足其存储的需求。此时系统就需要进行额外的操作。如根据存储引擎不同,有的会采用拆分机制,而有的则会采用分页机制。 

 CHAR数据类型与VARCHAR数据类型不同,其采用的是固定长度的存储方式。

  简单的说,就是系统总为其分配最大的存储空间。当数据保存时,即使其没有达到最大的长度,系统也会为其分配这么多的存储空间。显然,这种存储方式会造成磁盘空间的浪费。这里笔者需要提醒的一点是,当字符位数不足时,系统并不会采用空格来填充。相反,如果在保存CHAR值的时候,如果其后面有空值,系统还会自动过滤其空格。而在进行数据比较时,系统又会将空格填充到字符串的末尾。

  显然,VARCHAR与CHAR两种字符型数据类型相比,最大的差异就是前者是可变长度,而后者则是固定长度。在存储时,前者会根据实际存储的数据来分配最终的存储空间。而后者则不管实际存储数据的长度,都是根据CHAR规定的长度来分配存储空间。这是否意味着CHAR的数据类型劣于VARCHAR呢?其实不然。否则的话,就没有必要存在CHAR字符类型了。虽然VARCHAR数据类型可以节省存储空间,提高数据处理的效率。但是其可变长度带来的一些负面效应,有时候会抵消其带来的优势。为此在某些情况下,还是需要使用Char数据类型。

二、项目建议

  根据上面的分析,我们知道VARCHAR数据类型是一把双刃剑,其在带来性能提升的同时,也可能会存在着一些额外的消耗。我们在评估到底是使用VARCHAR数据类型还是采用CHAR数据类型时,就需要进行均衡。在实际项目中,我们会考量如下情况。

  一是根据字符的长度来判断

    如某个字段,像人的名字,其最长的长度也是有限的。如我们给其分配18个字符长度即可。此时虽然每个人的名字长度有可能不同,但是即使为其分配了固定长度的字符类型,即18个字符长度,最后浪费的空间也不是很大。而如果采用NVARCHAR数据类型时,万一以后需要改名,而原先的存储空间不足用来容纳新的值,反而会造成一些额外的工作。在这种情况下,进行均衡时,会认为采用CHAR固定长度的数据类型更好。在实际项目中,如果某个字段的字符长度比较短此时一般是采用固定字符长度。

  

  二是考虑其长度的是否相近

    如果某个字段其长度虽然比较长,但是其长度总是近似的,如一般在90个到100个字符之间,甚至是相同的长度。此时比较适合采用CHAR字符类型。比较典型的应用就是MD5哈希值。当利用MD5哈希值来存储用户密码时,就非常使用采用CHAR字符类型。因为其长度是相同的。另外,像用来存储用户的身份证号码等等,一般也建议使用CHAR类型的数据。

    另外请大家考虑一个问题,CHAR(1)与VARCHAR(1)两这个定义,会有什么区别呢?虽然这两个都只能够用来保存单个的字符,但是VARCHAR要比CHAR多占用一个存储位置。这主要是因为使用VARCHAR数据类型时,会多用1个字节用来存储长度信息。这个管理上的开销CHAR字符类型是没有的。

  

  三是从碎片角度进行考虑

    使用CHAR字符型时,由于存储空间都是一次性分配的。为此某个字段的内容,其都是存储在一起的。单从这个角度来讲,其不存在碎片的困扰。而可变长度的字符数据类型,其存储的长度是可变的。当其更改前后数据长度不一致时,就不可避免的会出现碎片的问题。故使用可变长度的字符型数据时,数据库管理员要时不时的对碎片进行整理。如执行数据库导出导入作业,来消除碎片。

  四是即使使用Varchar数据类型,也不能够太过于慷慨

    这是什么意思呢?如现在用户需要存储一个地址信息。根据评估,只要使用100个字符就可以了。但是有些数据库管理员会认为,反正Varchar数据类型是根据实际的需要来分配长度的。还不如给其大一点的呢。为此他们可能会为这个字段一次性分配200个字符的存储空间。这VARCHAR(100)与VARCHAR(200)真的相同吗?结果是否定的。虽然他们用来存储90个字符的数据,其存储空间相同。但是对于内存的消耗是不同的。对于VARCHAR数据类型来说,硬盘上的存储空间虽然都是根据实际字符长度来分配存储空间的,但是对于内存来说,则不是。其时使用固定大小的内存块来保存值。简单的说,就是使用字符类型中定义的长度,即200个字符空间。显然,这对于排序或者临时表(这些内容都需要通过内存来实现)作业会产生比较大的不利影响。所以如果某些字段会涉及到文件排序或者基于磁盘的临时表时,分配VARCHAR数据类型时仍然不能够太过于慷慨。还是要评估实际需要的长度,然后选择一个最长的字段来设置字符长度。如果为了考虑冗余,可以留10%左右的字符长度。千万不能认为其为根据实际长度来分配存储空间,而随意的分配长度,或者说干脆使用最大的字符长度。

从数据库实际角度考虑

   字符型字段是数据库表中最常见的字段,而字符型字段又分为定长和变长两种。一般来说,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),这对应用系统的运行和维护都是非常不利的。不针对字段的特点进行精确的描述,就不便于精确地理解业务模型,随着应用系统功能的不断扩充和升级,整个系统模型就会越来越模糊,直至无法维护,最后只好推翻重来,这个代价是非常大的。

sql-char和varchar,nvarchar的区别的更多相关文章

  1. char nchar varchar nvarchar的区别(转)

    char nchar  varchar nvarchar的区别   今天在论坛里看到有人激烈讨论这几个数据类型的区别跟实际使用情况,很多人都搞不清楚究竟哪个场景使用哪个数据类型 现在就摘录一下sql2 ...

  2. char nchar varchar nvarchar varchar2区别

    char(n):长度不可变,长度为n个字节,非Unicode字符 nchar(n):长度不可变,长度为2n个字节,Unicode字符 varchar(n):长度可变,长度为n个字节,非Unicode字 ...

  3. 万答#11,MySQL中char与varchar有什么区别

    万答#11,MySQL中char与varchar有什么区别 1.实验场景 GreatSQL 8.0.25 InnoDB 2.实验测试 2.1 区别 参数 char varchar 长度是否可变 定长 ...

  4. char/varchar/nvarchar的区别

    原文:https://blog.csdn.net/w516162189/article/details/78914035 我们在设计数据库的时候,需要根据需求场景选择合适的字段类型,对数据的执行效率有 ...

  5. 知识点:SQL中char、varchar、text区别

    Char为定长,varchar,text为变长. 1.CHAR.CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去1 ...

  6. char、varchar、varchar2区别

    char varchar varchar2 的区别 区别:1.CHAR的长度是固定的,而VARCHAR2的长度是可以变化的, 比如,存储字符串“abc",对于CHAR (20),表示你存储的 ...

  7. 数据库中char与varchar类型的区别

    在建立数据库表结构的时候,为了给一个String类型的数据定义一个数据库的数据库类型,一般参考的都是char或者varchar,这两种选择有时候让人很纠结,今天想总结一下它们两者的区别,明确一下选择塔 ...

  8. MySQL中char和varchar有啥区别?优缺点是啥?

    在mysql教程中char与varchar的区别呢,都是用来存储字符串的,只是他们的保存方式不一样罢了,char有固定的长度,而varchar属于可变长的字符类型. char与varchar的区别 c ...

  9. mysq中char,varchar,text的区别

    mysql5.0.3以后,n都表示字符数(varchar(n)) 检索效率 char > varchar > text 当varchar长度超过255之后,跟text一致,但是设置varc ...

  10. SqlServer中-char varchar nvarchar的区别

    说说nvarchar和varchar的区别:的区别: varchar:  可变长度,存储ANSI字符,根据数据长度自动变化. nvarchar: 可变长度,存储Unicode字符,根据数据长度自动变化 ...

随机推荐

  1. 孙鑫视频学习:改变窗口过程函数中出现error C2440错误的解决方法

    在Visual Studio 2010中,即使代码是完完全全按照孙鑫视频中的敲,也会在出现error C2440,这是因为开发平台由VC6.0升级至VS2010,需要将原有的项目迁移.VS2010对消 ...

  2. 阿里巴巴Druid数据源,史上最强的数据源,没有之一

    目前常用的数据源主要有c3p0.dbcp.proxool.druid,先来说说他们Spring 推荐使用dbcp:Hibernate 推荐使用c3p0和proxool1. DBCP:apacheDBC ...

  3. C#中treeview的问题,如何区分根节点和子节点以及根节点和根节点的兄弟节点?

    根节点的Level属性为0,一级子节点Level属性为1,二级子节点Level属性为2,以此类推:同级节点可以用索引.名称.文本来区分.用索引区分根节点时,TreeView.Nodes[0]就是第一个 ...

  4. Android ActionBarDrawerToggle、DrawerLayout、ActionBar 结合

    ActionBarDrawerToggle是一个开关,用于打开/关闭DrawerLayout抽屉 ActionBarDrawerToggle 提供了一个方便的方式来配合DrawerLayout和Act ...

  5. smarty模板继承

  6. Cobbler自动化批量安装linux服务器的操作记录

    Cobbler为何物?Cobbler是一个快速网络安装linux的服务,而且在经过调整也可以支持网络安装windows.该工具使用python开发,小巧轻便(才15k行python代码),使用简单的命 ...

  7. 18SpringMvc_在业务控制方法中收集数组参数

    这篇文章我们要解决的问题的多选框选中,并批量删除. 比如:

  8. C# 无边框窗体边框阴影效果

    通过下面代码在构造函数中调用方法 SetShadow(); 即可实现无边框窗体的阴影效果了 需要添加命名空间 using System.Runtime.InteropServices; private ...

  9. VisualStudio2013+EF6+MySql5.5环境下配置

    看院子里对EF框架和MySql的配置文章不少,但是几乎出自一篇文章的转载,而且这篇转载的文章的也比较坑爹,下面我将介绍一下我的配置过程: 第一步:安装mysql-connector-net-6.9.9 ...

  10. PKI公钥处理思路

    背景: 在使用任何基于RSA服务之前,一个实体要真实可靠的获取其他实体的公钥.   1,一个可以确认公钥身份的方案:[离线确认] 主:B做同样的事情得到A的公钥. 但是这种方法扩展性差,不可行.   ...