Fork me on GitHub

MySQL数据类型补充

我们知道,使用varchar类型存储时,需要使用1或2个字节记录字符串的长度:如果列的最大长度小于或等于255字节,则只使用一个字节表示,否则使用两个字节。

假设以下描述使用的都是UTF-8编码,存入英文字符。

即varchar(255)使用了256个字节,而varchar(256)则使用了258个字节。

那么问题来了,我们在设计表的时候,如果不确定字段的最大长度,使用了变长字符串varchar类型,那么是不是不管三七二十一直接上varchar(255)呢(假设最大长度不超过255),按照之前的理论,varchar(10)和varchar(255)存储“hello”的空间开销都是一样的,即都是使用了5个字符的硬盘存储空间,但这个数据加载到内存的时候,就会使用固定大小的内存块来保存值。简单来说,就是两种方式在硬盘中存储空间开销并无二致,但在内存中就大有不同。

varchar(10)在内存中使用10个字符的内存空间,varchar(255)在内存中使用255个字符的内存空间。这对于排序或者临时表(需要通过内存操作来实现)作业会产生比较大的不利影响。

所以如果某些字段会涉及到文件排序或者基于磁盘的临时表时,分配VARCHAR数据类型时仍然不能够太过于慷慨。还是要评估实际需要的长度,然后选择一个最长的字段来设置字符长度。如果为了考虑冗余,可以留10%左右的字符长度。千万不能认为其为根据实际长度来分配存储空间,而随意的分配长度,或者说干脆使用最大的字符长度。

另一个问题:varchar的允许的最大字节长度是65535字节,那么varchar(?)这个?最大能是多少呢。

  • 非空字段时:最大可以到65533,2个字节用于记录字符串长度
  • 可空字段:最大可以到65532,2个字节用于记录字符串长度,一个字节用于及记录 null 值。

以上的结论是以UTF-8编码及全部存入英文字符为前提的理想状态,但实际上使用UTF-8时,varchar(?)到不了65532那么大,因为一个字符最大占用三个字节,MySQL默认存入以最大字节数来计算。

所以最大到达21844,21845*3=65535字节,虽然符合最大字节限制,但没有空间存放字符串长度的记录了。

查看数据库默认字符集

1
2
3
4
5
6
7
mysql> show variables like 'character_set_database';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| character_set_database | utf8 |
+------------------------+-------+
1 row in set (0.01 sec)

将varchar设置为21844,创建成功

1
2
mysql> create table test_varchar(v1 varchar(21844));
Query OK, 0 rows affected (0.03 sec)

大于21844则报错

1
2
3
4
5
6
7
mysql> mysql> create table > create table test_varchar(v1 varchar(65535))' at line 1
mysql> create table test_varchar(v1 varchar(65535));
ERROR 1074 (42000): Column length too big for column 'v1' (max = 21845); use BLOB or TEXT instead


mysql> create table test_varchar(v1 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