InnoDB存储引擎VARCHAR最多能存储的数据
前言
我们知道在InnoDB存储引擎中,行格式Compact、Compressed、Dynamic都会计算变长字段VARCHAR长度列表,这个字段长度一般采用两个字节表示,也就是VARCHAR能表示的最大长度应该是2的16次方(因为一个字节8位,两个字节16位能表示的最大值是65535),那么65535个字节长度是否能存放呢?测试案例如下
mysql> create table test_varchar_size(
-> c varchar(65535)
-> )CHARSET=ascii ROW_FORMAT=Compact;
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
分析
很明显错误信息提示,我们列c设置的长度太长,注意MySQL对一条记录占用最大的空间有限制,所有列(不包含隐藏列和记录头信息)长度之和需要小于65535,当然这并不包含TEXT或者BLOBs类型的列。也就是说test_varchar_size测试表还有其它数据占据空间,我们先来分析一条数据的基本信息,以Compact行格式为例
这里的长度不计算记录头信息以及隐藏列那么还剩下如下三部分数据
- 字段的真实数据。
- 字段的长度数据。
- 字段的NULL值列表。
ascii字符集
字段的长度数据也就是长度列表最大两个字节,字段c没有指明not null所以占用一个字节(只有一个字段其实只占用了一个bit位,但需要用一整个字节表示所以高位补0),而test_varchar_size测试表的的字符集为ascii,只需要用一个字节就可以表示一个字符,其余编码集可以参考如下数据。
### 查询所有的字符集,总共有41种下面抽取常见字符集
### Maxlen表示一个字符最大需要几个字节表示
mysql> show charset;
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| ascii | US ASCII | ascii_general_ci | 1 |
| gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 |
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |
.......
+----------+---------------------------------+---------------------+--------+
所以采用ascii的测试表test_varchar_size唯一c字段长度应该为
65535 - 2(变长字符长度列表)-1(NULL值列表)= 65532
mysql> create table test_varchar_size(
-> c varchar(65532)
-> )CHARSET=ascii ROW_FORMAT=Compact;
Query OK, 0 rows affected (0.01 sec)
在上面分析中我们提到了字符集影响字段c的最大长度,那么非ascii是如何影响的呢?往下面走
gbk字符集
通过show charset like '%gbk%';命令我们可以得到gbk一个字符最大需要两个字节才能表示,演示如下
mysql> show charset like '%gbk%';
+---------+------------------------+-------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+------------------------+-------------------+--------+
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
+---------+------------------------+-------------------+--------+
1 row in set (0.00 sec)
那么采用gbk字符c字段能表示的最大长度应该为
65535 - 2(变长字符长度列表)-1(NULL值列表)= 65532
65532 / 2 = 32766
结果验证如下
mysql> create table test_varchar_size(
-> c varchar(32767)
-> )CHARSET=gbk ROW_FORMAT=Compact;
ERROR 1118 (42000): Row size too large. The maximum row size
for the used table type, not counting BLOBs.......
mysql> create table test_varchar_size(
-> c varchar(32766)
-> )CHARSET=gbk ROW_FORMAT=Compact;
Query OK, 0 rows affected (0.01 sec)
utf8字符集
utf8字符集验证和gbk字符集验证类似,因为utf8一个字符需要三个字节表示,所以c字段能表示的最大长度就是
65532 / 3 = 21844
注意
上面分析时只采用了一个字段,并且字段c是允许为空的,就直接采用上面的规则分析,如果c字段设置了NOT NULL那么就不需要65535-1的操作,实际分析时需要根据情况具体分析。