一、varchar(M)列的定义限制
其中M指的是可存储的字符长度(或字符数),而MySQL实际是按字节存储的,在不同的字符集下一个字符的字节长不同,因此这个M最大值在不同的字符集下值不同:
对于latin字符集下,因为一个字符占一个字节,所以M的最大值为65535(但实际只有65532);对于gbk字符集,因为一个字符占两个字节,所以M的最大值为32767;对于utf8字符集,因为一个字符占两到三个字节,所以M的最大值为21845。
此外,mysql官方文档中定义的65535长度是指同一行的所有varchar列的长度总和。如果列的长度总和超出这个长度,依然无法创建。
1、MySQL5.6的限制方式:
在MySQL5.6版本中,当某个列的varchar长度定义超过相应字符集下的最大长度时,会自动将该列转存为mediumtext类型。例如,在utf8字符集下,定义ecs_payment表test2字段长度为21846:
可以看到test2字段被存为mediumtext类型。
假如再存储一个字段test3,定义varchar长度为21845,这时没有超过最大长度限制,但在存储test3 varchar(21845)列时,发现该表上所有varchar行的总长度将会超过65535字节,因此会发生如下报错:
mysql> alter table ecs_payment add test3 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
2、MySQL5.7的限制方式:
在MySQL5.7版本下,只要列的varchar长度超过相应字符集下的最大限制,或者表上所有varchar列总长度将会超过65535字节时,MySQL都会抛出错误提示:
mysql> alter table t1 add c1 varchar(21846);
ERROR 1074 (42000): Column length too big for column 'c1' (max = 21845); use BLOB or TEXT instead
mysql> alter table t1 add c1 varchar(21844);
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
二、创建索引的限制
对于varchar列,当varchar长度过长时,会对索引的创建有限制,在MySQL5.6和5.7下的限制行为的表现形式不同。
1、MySQL5.6的限制
在MySQL5.6中,对ecs_payment表的test varchar(1024)列创建索引,并查看创建后的情况:
可以看到test列上建立了一个前缀索引,前缀长度为255字节。在MySQL5.6下,varchar长度超过255字节时是不适合建立索引的,MySQL会自动只建立255字节长的前缀索引,而不是抛出错误。
2、MySQL5.7的限制
在MySQL5.7版本下,varchar列上可建索引的最大长度是3072字节,超过此长度在建索引时会报错:
mysql> alter table t1 add column c4 varchar(1025);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> create index i_2 on t1(c4);
ERROR 1071 (42000): Specified key was too long; max key length is 3072 bytes
表t1是utf8字符集。