我们都知道MySQL中有两种常用的字符类型,char和varchar。也许在平时的使用中,你不会在意这两种类型的区别。只是知道怎么用,或者看到了一些区别,但是没时间去测试。我今天有时间。我会针对这两种类型的具体情况进行实验,让大家直观感受。纯粹是为了分享,大神请绕道。先说理论。char类型是定长字符串,比如char(10),定义了指定字符串长度最多为10个字符。如果现在输入一个字符串为'12345678',那么它在char类型的末尾需要多少个字符?答案是10,MySQL会自动将缺少的2个字符补成空值,然后存储。取这条记录时,char类型会使用trim()函数去掉多余的空格,所以我们看到的还是一条8个字符的记录。当输入的字符长度大于最大长度时,MySQL会自动报错。varchar类型是可变长度的字符串。varchar(M)表示最大长度为M个字符。varchar的最大实际长度由最大行大小和使用的字符集决定。例如varchar(50)定义了一个最大长度为50的字符串,如果插入的字符串只有20个字符,那么实际存储的字符串将有21个字符,因为varchar会自动包含一个字符串结束符。varchar在保存和取值的时候,尾部的空格还是保留的。介绍完概念,我们来看看具体的实践过程。本文使用的测试版本为MySQL5.7.22。1、测试char的trim()函数首先创建一个表,表中包含d_char和d_varchar两个字段,并设置初始字符长度为4,如下:查一下。此时我们插入两条记录,每条记录都是'ab',注意ab后面有2个空格,然后我们使用mysql中的concat函数进行字符拼接,每条记录左右加上括号.这时候我们可以看到d_charab后面的空格被取消了,d_varchar后面的空格依然存在。2.测试两种字符类型的最大长度首先看char的最大长度,我们设置的值为256,结果如下所以,char类型的长度范围是0到255个字符最大实际长度上面提到varchar的大小是由最大行的大小和使用的字符集决定的。这里我们做个实验:可以看到,字符集不同,最终的最大值也不同。utf8模式下为0~21845,1个字符占3个Bytes,最多可存储21844个字符。latin1模式下为0~65535。一个字符占一个字节,最多可存储65532个字符。gbk模式下为0~32767。一个字符占两个字节,最多可以存储32766个字符,定义时如果超过上述限制,varchar字段将被强制转换为text类型,并产生警告。可能看到这里有人会问,为什么最大值是32767,但是最多只能放32766个字符呢?举两个例子来说明实际长度的计算。a)如果一张表只有一种varchar类型,比如定义为createtablet4(cvarchar(N))charset=gbk;那么这里N的最大值就是(65535-1-2)/2=32766个字符。之所以减1是因为实际的行存储是从第二个字节开始的';减2的原因是varchar头中的2个字节表示长度;除以2的原因是字符编码是gbk。b)如果表定义为createtablet4(cint,c2char(30),c3varchar(N))charset=utf8;那么这里N的最大值就是(65535-1-2-4-30*3)/3=21812负1和负2同上例;负4的原因是int类型的c占用4个字节;负30*3的原因是char(30)占用90个字节,编码为u??tf8。如果varchar超出了上面的b规则,强制转换为text类型,则每个字段占用11个字节的定义长度。当然,这不再是“varchar”。那么这里N的最大值就是(65535-1-2-4-30*3)/3=218123。MySQL的字段长度模式字段长度模式分为严格模式和非严格模式。在严格模式下,如果我们要在一个字段中插入大于指定长度的字符串,mysql会给出错误信息,比如我们的表:当我们插入一条大于4个字符的记录时,如果在非严格模式下,mysql将自动截断超过最大长度的字符。上面的操作是我们先将字段模式改为非严格模式,然后查询修改,确保修改生效。然后我们插入'abcde'字符串,发现可以执行成功,但是包含两个警告。查看warnings可以发现有些数据被截断了。实验部分内容基本完成。下面我们做一些分析:1.MySQL为什么要设置这两种类型?它们各自的优点是什么?char是定长的,存取速度比varchar快,方便程序存储和查找,但需要浪费一定的空间,可以看作是一种用空间换取时间的方法。varchar的特点是变长。当定义了一个varchar(10),只存储了4个字符时,varchar会直接将字符记录的长度改为4,从而节省空间。可以看作是一种以时间换空间的方式。char的存储方式是英文字符(ASCII)占1个字节,一个汉字占2个字节;而varchar的存储方式是每个英文字符占2个字节,汉字占2个字节。bytes,两者的存储数据都是非unicode字符数据。2.两种类型的适应情况分析。关于char:CHAR适合存储很短的字符串,或者所有的值都接近相同的长度。对于经常变化的数据,CHAR也比VARCHAR好,因为定长的CHAR类型不容易产生碎片。就非常短的列的存储空间而言,CHAR也更有效。比如使用char(1)只存储Y和N值只需要一个字节,但是varchar需要两个字节,因为记录长度多了一个字节。关于varcharVARCHAR类型用于存储变长字符串,是最常见的字符串数据类型。它比定长类型更节省空间,因为它只使用必要的空间(例如,较短的字符串使用较少的空间)。VARCHAR节省存储空间,因此它也有助于提高性能。但是,由于该行的长度是可变的,UPDATE可能会使该行比原始行更长,从而导致额外的工作。如果一行占用的空间增长,页面中没有更多的空间存储它,不同的存储引擎对这种情况的处理方式不同。比如MyISAM会把行拆分成不同的分片进行存储,而InnoDB则需要拆分页面,让行能装进页面。VARCHAR需要使用1或2个额外的字节来记录字符串的长度:如果列的最大长度小于等于255字节,则只用1字节表示,否则用2字节表示。假设使用latinl字符集,一个varchar(10)列需要11个字节的存储空间。varchar(1000)列需要1002个字节,因为需要2个字节来存储长度信息。适用条件:1、对于MyISAM表,尽量使用Char,尤其是myisam和isam数据表经常需要修改,容易产生碎片。它的缺点是占用磁盘空间;2.对于InnoDB表,由于其数据行的内部存储格式不区分定长数据行和变长数据行(所有数据行共享一个表头部分,表头部分存储指向相关数据列的指针),所以使用char类型不一定比使用varchar类型好。事实上,由于char类型通常比varchar类型占用更多的空间,所以从减少空间占用和磁盘I/O的角度来看,使用varchar类型更有好处;3.存储很短的信息,比如门牌号码Numbers101,201...这种很短的信息应该用char,因为varchar也占用一个字节来存储信息的长度,原计划省存储不值得蜡烛。4.定长。比如用uuid作为主键,用char应该比较合适。因为它有固定的长度,所以varchar会根据长度特性动态消失,同时也会占用长度信息。5.变化非常频繁的列。因为varchar每次存储的时候都需要额外的计算,获取长度等工作,如果变化的很频繁,计算会消耗很多能量,而char不需要这些。关于MySQL的char和varchar,你了解过吗?
