CHAR和VARCHAR是最常使用的两种字符串类型。一般来说,CHAR(N)用来保存固定长度的字符串,VARCHAR(N)用来保存变长字符类型。对于CHAR类型,N的范围为0~255,对于VARCHAR类型,N的范围为0~65 535。CHAR(N)和VARCHAR(N)中的N都代表字符长度,而非字节长度。

注意 对于MySQL 4.1之前的版本,如MySQL 3.23和MySQL 4.0,CHAR(N)和VARCHAR(N)中的N代表字节长度。


MySQL5的文档,其中对varchar字段类型这样描述:varchar(m) 变长字符串。M 表示最大列长度。M的范围是0到65,535。(VARCHAR的最大实际长度由最长的行的大小和使用的字符集确定,最大有效长度是65,532字节)

编码长度限制
字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766
字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845

若定义的时候超过上述限制,则varchar字段会被强行转为text类型,并产生warning。




a)比如:若一个表只有一个varchar类型,如定义为 若一个表只有一个varchar类型,如定义为

create table t4(c varchar(N)) charset=gbk;
则此处N的最大值为(65535-1-2)/2= 32766。
减1的原因是实际行存储从第二个字节开始';
减2的原因是varchar头部的2个字节表示长度;
除2的原因是字符编码是gbk

b) 若一个表定义为
create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;
则此处N的最大值为 (65535-1-2-4-30*3)/3=21812
减1和减2与上例相同;
减4的原因是int类型的c占4个字节;
减30*3的原因是char(30)占用90个字节,编码是utf8。
如果被varchar超过上述的b规则,被强转成text类型


MYSQL COMPACT格式,每条记录有一个字节来表示NULL字段分布,如果表中有字段允许为空,则最大只能定到65532,如果没有字段允许为空,则那个字节可以节省,最大可以定义到65533

1.create table test(name varchar(65533) not null)engine=innodb DEFAULT CHARSET=latin1  (可以正确执行,最大能到65533)

2.create table test(name varchar(65533))engine=innodb DEFAULT CHARSET=latin1
对于这种情况,允许空字段的时候是不能加到65533的长度的,最大只能到65532,

name varchar(100) not null will be 1 byte (length) + up to 100 chars (latin1)
name varchar(500) not null will be 2 bytes (length) + up to 500 chars (latin1)
name varchar(65533) not null will be 2 bytes (length) + up to 65533 chars (latin1)
name varchar(65532) will be 2 bytes (length) + up to 65532 chars (latin1) + 1 null byte

总结一下,原来mysql的vachar字段的类型虽然最大长度是65535,但是并不是能存这么多数据,最大可以到65533(不允许非空字段的时候),当允许非空字段的时候只能到65532。


极少数用char的情况:

当一个列的值都是固定长度的时候,比如是10  ,此时用char(10),则只用char(10)所占的字节,

但如果用varchar(10),则所占的为varchar(11)所占的字节,因为varchar需要在前面加上代表长度的字节。(同CHAR对比,VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节))。


varchar(100)与varchar(200)的区别:

对于VARCHAR数据类型来说,硬盘上的存储空间虽然都是根据实际字符长度来分配存储空间的,但是对于内存来说,则不是。其实使用固定大小的内存块来保存值。简单的说,就是使用字符类型中定义的长度,即200个字符空间。显然,这对于排序或者临时表(这些内容都需要通过内存来实现)作业会产生比较大的不利影响

二者在磁盘上存储占的空间是一样的。区别有三。

第一:一个变长一个固定长度。

第二:在内存中的操作方式,varchar也是按照最长的方式在内存中进行操作的。比如说要进行排序的时候,varcahr(100)是按照100这个长度来进行的。


第三:

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


D.7.4 Limits on Table Column Count and Row Size

There is a hard limit of 4096 columns per table, but the effective maximum may be less for a given table. The exact limit depends on several interacting factors.

  • Every table (regardless of storage engine) has a maximum row size of 65,535 bytes. Storage engines may place additional constraints on this limit, reducing the effective maximum row size.

BLOB and TEXT columns count from one to four plus eight bytes each toward the row-size limit because their contents are stored separately from the rest of the row.

上面的意思是在处理blob和text类型时!mysql最大行字节65535这个限制是这样子的:

blob和text类型分别按1到4 加上8个字节算!也就是一个blob和text类型按2+8个字节算!tinyblob和tinytext按1+8=9个字节算!mediumtest,mediumblob,longtext,longblob 分别按3+8,4+8个字节算!为什么可以这样子呢?是因为blob和text的内容是分开存储在剩下的行中的!


例如:mysql每行最字节数65535,但我们一般使用utf8编码,那么存取字符数为65532/8=21844个(去除掉三个字节一个用来表示是否为Null,另二个用来表示字段长度),那么:

create table a (a varchar(65532));

ERROR 1074 (42000): Column length too big for column 'a' (max = 21845); use BLOB or TEXT instead

create table a (a varchar(21845));

ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

create table a (a varchar(21844));

Query OK, 0 rows affected (0.44 sec)   //成功


create table b (a varchar(21844),b text);  //当加上一个text字段时

ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs


create table b (a varchar(21841),b text); //这里相比上面21844减了三个字符!相当于腾出9个字节,但依然报错!

ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs


create table b (a varchar(21840),b text);

Query OK, 0 rows affected (0.25 sec)  //成功,

总结原因:在满足mysql最大行字节65532的时候,加上的b text字段需占用2+8=10个字节!

再举一例验证:

 create table c (a varchar(21841),b tinytext);   

Query OK, 0 rows affected (0.19 sec) //tinytext字段需给他腾出1+8=9个字节,  成功


create table e (a varchar(21842),b tinytext); 

ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs    //这里只给腾出6个字节,所以报错!