InnoDB行格式(3)VARCHAR最多能存储的数据

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的操作,实际分析时需要根据情况具体分析。

 

posted on   Java面试365  阅读(71)  评论(0编辑  收藏  举报

编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示