CHAR 与 VARCHAR的区别

来源:互联网 发布:软件项目沟通计划 编辑:程序博客网 时间:2024/06/15 09:13

为什么要谈CHAR与VARCHAR?
大家可能都想CHAR和VARCHAR这种东西再简单不过了,只不过是MySQL中最基本的数据类型,有什么好深究的。其实有时候越简单、越基础的东西越复杂,越难以捉摸。
大家在使用MySQL创建数据表时都会遇到这样的问题,如何为字段选择合适的数据类型,熟悉这些基本数据类型将会让你从容地应对,做到建表时的优化。今天我们就来探究一下MySQL中的CHAR和VARCHAR。

先来热热身
CHAR和VARCHAR类型相似,都用来存储字符串,但是它们的存储和检索方式不同,在允许的最大长度和是否保留尾部空格上也有差异。
其中最重要的区别就是CHAR是定长的字符类型,而VARCHAR属于变长的字符类型。
那么什么时候使用CHAR,什么时候使用VARCHAR,别急,我们继续下去就知道了。

开始我们的征途
主持人:今天我们有幸请来了MySQL家族中的两位大拿来到现场,大家猜猜他们是谁呢?(一阵等待,音调提高)他们分别是CHAR与VARCHAR,大家掌声欢迎他们进场。(雷鸣般的掌声)

CHAR和VARCHAR(异口同声):谢谢主持人,谢谢观众朋友!

主持人:众所周知,人们经常滥用混用你们两位(CHAR和VARCHAR一副赞同脸)。今天也有幸请到了你们二位,也希望作为当事人的你们给大家一个完美的阐述。

VARCHAR:主持人,你的此番言语可谓是触动了我和CHAR两兄弟的内心深处的那根弦(感动的样子)。我用来存储可变长字符串,而CHAR兄弟用来存储定长字符串,也就不知道大家怎么能把我们两兄弟给搞混呢?

CHAR:VARCHAR老哥,你说的对啊。我们两虽然类型相似,都用来保存字符串,但是在存储方式和检索方式上都有差异。

VARCHAR:并且我们在最大长度和是否保留尾部空格都不尽相同。(一片嘘声)

主持人:额额呢,以上两位简单阐述了你们的区别,不知道能否具体说明一下呢?

VARCHAR:那我先来说说,我是VARCHAR,我可以存储长度为(0-65535字节)的可变长度字符串,这个长度同时也受限于数据库或者数据表所使用的字符集(如果是UTF-8,这里可以指定的最大长度为21844,GBK则为32766),它可以占用更少的存储空间。
我的存储方式是:一个或两个字节的长度前缀+具体数据。
这里一个或两个字节的长度前缀指的是:我会根据需要采用1个或者2个额外的字节来记录字符串(具体数据)的长度。如果列的最大长度小于或者等于255字节,则只使用1个字节来表示,否则使用2个字节。因为我的最大长度为65535,所以两个字节就足以表示我的数据的长度。

CHAR:我是CHAR,我能存储(0-255字节)的定长字符串。举个例子,CHAR(10)可以存储长度为10的定长字符串,当长度不够或者不满10的时候,我会采取在尾部追加空格的方式让所有的字符串都达到指定的长度10,当长度大于10的时候,超过长度的值都不会保存(如果运行在严格模式下,超过长度的值也不会保存,但是会出现错误提示),这是我存储数据的格式。当我检索数据的时候,我会删除所有的尾部空格(除非开启 PAD_CHAR_TO_FULL_LENGTH模式),而VARCHAR老哥在检索的时候则不会去除尾部空格。大家可以看看以下的测试:

mysql> CREATE TABLE char_test(char_col CHAR(10));mysql> INSERT INTO char_test(char_col)     -> VALUES ('String1'),(' String2'),('String3 ');mysql> SELECT char_col,LENGTH(char_col) FROM char_test;

当检索这些值的时候,会发现String3末尾的空格被去除了。
这里写图片描述

如果用VARCHAR(10)字段存储相同的值,可以得到如下结果:
这里写图片描述
这是我们两一个重要的区别。

上面VARCHAR老哥说的也十分好,但是有一点我不能苟同,就是将字段定义为他占用的存储空间更少。对于非常短的列来说,我比VARCHAR老哥做的稍微好点,例如用CHAR(1)来存储只有Y和N的值,采用我,就只需要一个字节,而VARCHAR老哥却需要两个字节,因为还有一个记录长度的字节。还有,大家看看下面的数据:


ValueCHAR(4)Storage RequiredVARCHAR(4)Storage Required'abcd''abcd'4 bytes'abcd'5 bytes 'abc''abc '4 bytes'abc'4 bytes'ab''ab  '4 bytes'ab'3 bytes

在表中第一行,此时VARCHAR老哥还需要花费一个字节存储自己有效数据的长度,而我不需要,此时应是我占用的存储空间更少。第二行的数据显示我们占用的存储空间相等。在第三行,则是VARCHAR老哥更胜一筹。
综合上面三条记录来看,所占用的空间都为12bytes,这里是因为字符串长度分布得十分均匀,那么如果不均匀,也就是字符串列的最大长度比平均长度大很多的时候,这时候VARCHAR老哥就可以大展身手了。

VARCHAR:看来CHAR老弟对我的了解有点深刻啊(微微一笑),大家注意CHAR老弟的这一句,在字符串列的最大长度比平均长度大很多的时候,使用我比较好。为什么要大很多呢?不是大2个字节,相比之下,我的存储空间就已经占用少了。
先来听我说说:采用我,虽然说节省了存储空间,但是由于行是变长的,在update的时候可能使行变得比原来更长,这就导致需要做许多额外的工作。如果一个行占用的空间增长,并且在页内没有更多的空间可以存储,在这种情况下,不同的存储引擎处理方式是不一样的。例如,MyISAM会将行拆分成不同的片段进行存储,InnoDB则需要分裂页来使行可以放进页内。
在这种情况下,容易产生碎片,在这里如果大家想使用我的话,得做一下折中。对于那种经常变更且字符长度比较接近的字符列使用CHAR老弟还是更胜一筹,因为定长的CHAR类型不容易产生碎片。

主持人:说了这么多,不知道你们可以简短概括或者说总结一下吗?

CHAR:我代表VARCHAR老哥和我来总结一下今天我们的谈话,希望大家至少记住以下几点:

总结
1. CHAR类型是定长的,CHAR类型存储最大的字符长度为255,VARCHAR类型是变长的,最大长度为65535;
2. 定义为CHAR的列在存储时会在尾部补上必要的空格,而在检索的时候会移除尾部的空格;
3. 在字符串列的最大长度比平均长度大很多的情况或者列更新很少(因为VARCHAR有可能产生碎片)的情况下,优先考虑VARCHAR类型;
4. CHAR适合存储很短的字符串,或者所有值都接近同一个长度,例如CHAR值非常适合存储密码的MD5值,邮政编码,手机号码,性别之类的。对于经常变更的数据且字符长度差异不大的情况下,CHAR比VARCHAR更好,因为定长的CHAR不易产生碎片。

主持人:今天的节目到此为止,在此万分感谢二位的到来,也谢谢大家的观看!

原创粉丝点击