MySQL中varchar(n) 中 n 最大取值为多少?

大家好,我是小林。
上周发了一篇字节一面:mysql 的 null 值是怎么存放的?,文章里面有提及这个问题:「varchar(n) 中 n 最大取值为多少?」
当时这部分内容写的不够严谨,所以我重写了这部分内容。
所以,这次就聊聊这个问题。
前置知识 要回答这个问题,首先我们得先知道 mysql 存储一条记录的格式长什么样子。
以  compact 行格式作为例子,它长这样:
可以看到,一条完整的记录分为「记录的额外信息」和「记录的真实数据」两个部分。
这里重点讲讲记录的额外信息,它包含 3 个部分:变长字段长度列表、null 值列表、记录头信息。
变长字段长度列表 用于存储一行记录中每个变长字段的长度。
「变长字段长度列表」所占用的字节数 = 所有「变长字段长度」占用的字节数之和。
举个例子,假设数据库表中有 2 个 varchar(10) 类型的字段,分别为 a 和 b,且数据库表的字符集为 ascii 字符集(1 个字符占用 1 字节)。
那么a和b字段的数据值的长度分别只需要用1字节表示就行了,因为1字节能表示最大的字节数是 255,而 varchar(10) 类型的字段最大允许存储的字节数是 10 字节,所以只需要用 1 字节表示变长字段的长度就行。
那么这种情况下的 「变长字段长度列表」所占用的字节数 = 1 字节 + 1字节 = 2 字节。
「变长字段长度列表」不是必须的,如果数据库表没有变长字段,比如字段类型都是int,那么行格式中就不需要「变长字段长度列表」。
null 值列表 用于标记一行记录中字段值为 null 的字段,二进制位的值为 1 时,代表该字段的值为null,二进制位的值为 0 时,代表该字段的值不为 null。
另外,null 值列表必须用整数个字节的位表示(1字节8位),如果使用的二进制位个数不足整数个字节,则在字节的高位补 0。
如果表中允许为 null 值的记录的个数小于等于 8 个,那么 null 值列表就会用 1 字节表示。
如果如果表中允许为 null 值的记录的个数大于8 并且小于等于 16,那么 null 值列表就会用 2 字节表示,以此类推。
因此,如果表中有字段允许为 null,那么「null 值列表」至少占用 1 字节空间。
「null 值列表」不是必须的,如果数据库表中的字段都定义成 not null,那么行格式中就不需要「null 值列表」。
记录头信息 记录头信息中包含的内容很多,比如记录的删除标记位,指向下一条记录的指针等等,不是本文问题的重点,所以我就不细讲了。
varchar(n) 中 n 最大取值为多少? 我们要清楚一点,mysql 规定除了 text、blobs 这种大对象类型之外,其他所有的列(不包括隐藏列和记录头信息)占用的字节长度加起来不能超过 65535 个字节。
也就是说,一行记录除了 text、blobs 类型的列,限制最大为 65535 字节,注意是一行的总长度,不是一列。
知道了这个前提之后,我们再来看看这个问题:「varchar(n) 中 n 最大取值为多少?」
varchar(n) 字段类型的 n 代表的是最多存储的字符数量,并不是字节大小哦。
要算 varchar(n) 最大能允许存储的字节数,还要看数据库表的字符集,因为字符集代表着,1个字符要占用多少字节。
比如 ascii 字符集, 1 个字符占用 1 字节,那么  varchar(100) 意味着最大能允许存储 100 字节的数据。
单字段的情况 前面我们知道了,一行记录最大只能存储 65535 字节的数据。
那假设数据库表只有一个 varchar(n) 类型的列且字符集是 ascii,在这种情况下, varchar(n) 中 n 最大取值是 65535 吗?
不着急说结论,我们先来做个实验验证一下。
我们定义一个 varchar(65535) 类型的字段,字符集为 ascii 的数据库表。
create table test ( `name` varchar(65535)  null) engine = innodb default character set = ascii row_format = compact; 看能不能成功创建一张表:
结果显示,创建失败了。
从报错信息就可以知道一行数据的最大字节数是 65535(不包含 text、blobs 这种大对象类型),其中包含了 storage overhead。
问题来了,这个 storage overhead 是什么呢?其实就是「变长字段长度列表」和 「null 值列表」。
也就是说一行数据的最大字节数 65535,其实是包含「变长字段长度列表」和 「null 值列表」所占用的字节数的。
所以, 我们在算 varchar(n) 中 n 最大值时,需要减去 storage overhead  占用的字节数。
这是因为我们存储字段类型为 varchar(n)  的数据时,其实分成了三个部分来存储:
真实数据 真实数据占用的字节数 null 标识,如果不允许为null,这部分不需要 本次案例中,「null 值列表」所占用的字节数是多少?
前面我创建表的时候,字段是允许为 null 的,所以会用 1 字节来表示「null 值列表」。
本次案例中,「变长字段长度列表」所占用的字节数是多少?
「变长字段长度列表」所占用的字节数 = 所有「变长字段长度」占用的字节数之和。
所以,我们要先知道每个变长字段的「变长字段长度」需要用多少字节表示?具体情况分为:
条件一:如果变长字段允许存储的最大字节数小于等于 255 字节,就会用 1 字节表示「变长字段长度」; 条件二:如果变长字段允许存储的最大字节数大于 255 字节,就会用 2 字节表示「变长字段长度」; 我们这里字段类型是 varchar(65535) ,字符集是 ascii,所以代表着变长字段允许存储的最大字节数是 65535,符合条件二,所以会用 2 字节来表示「变长字段长度」。
因为我们这个案例是只有 1 个变长字段,所以「变长字段长度列表」= 1 个「变长字段长度」占用的字节数,也就是 2 字节。
因为我们在算 varchar(n) 中 n 最大值时,需要减去 「变长字段长度列表」和 「null 值列表」所占用的字节数的。
所以,在数据库表只有一个 varchar(n)  字段且字符集是 ascii 的情况下,varchar(n) 中 n 最大值 =  65535 - 2 - 1 = 65532。
我们先来测试看看  varchar(65533)  是否可行?
可以看到,还是不行,接下来看看 varchar(65532)  是否可行?
可以看到,创建成功了。说明我们的推论是正确的,在算 varchar(n) 中 n 最大值时,需要减去 「变长字段长度列表」和 「null 值列表」所占用的字节数的。
当然,我上面这个例子是针对字符集为 ascii 情况,如果采用的是 utf-8,varchar(n)  最多能存储的数据计算方式就不一样了:
在 utf-8 字符集下,一个字符串最多需要三个字节,varchar(n) 的 n 最大取值就是 65532/3 = 21844。 上面所说的只是针对于一个字段的计算方式。
多字段的情况 如果有多个字段的话,要保证所有字段的长度 + 变长字段字节数列表所占用的字节数 + null值列表所占用的字节数 <= 65535。
这里举个多字段的情况的例子。
实验结果:
总结 varchar(n) 中 n 最大取值为多少?
一行记录最大能存储 65535 字节的数据,但是这个是包含「变长字段字节数列表所占用的字节数」和「null值列表所占用的字节数」。所以, 我们在算 varchar(n) 中 n 最大值时,需要减去这两个列表所占用的字节数。
如果一张表只有一个 varchar(n)  字段,且允许为 null,字符集为 ascii。varchar(n) 中 n 最大取值为 65532。
计算公式:65535 - 变长字段字节数列表所占用的字节数 - null值列表所占用的字节数 = 65535 - 2 - 1 = 65532。
如果有多个字段的话,要保证所有字段的长度 + 变长字段字节数列表所占用的字节数 + null值列表所占用的字节数 <= 65535。
历史好文:
字节一面:http 长连接和 tcp 长连接有区别?
美团三面:一直追问我, mysql 幻读被彻底解决了吗?
保姆级教程!2 万字 + 30 张图搞懂 mysql 是怎么加行级锁的?
mysql 全局锁、表级锁、行级锁,你搞清楚了吗?


2020年度中国工业互联网的十件大事
风冷控制柜的优点
关于三星870 QVO固态硬盘内部的实测性能
采用三片机芯JG-988型散件进行黑白电视机的安装与调试
低成本FPGA中实现动态相位调整方案
MySQL中varchar(n) 中 n 最大取值为多少?
推进工业互联网落地实施需要强化融合发展的支撑条件
曲面屏手机:这四款颜值最高!最后一款不是谁都买得起
科大讯飞翻译机3.0的全新上市,新一波的智能语音翻译浪潮又席卷而来
乐Pro3:骁龙821+6G+4070mAh,仅2099
马云今年大手笔入医疗,开无人超市,入局租房,目的只有一个8000亿美金冲锋美国硅谷
Rhombus 采用 Wolfspeed SiC 器件,实现更快电动汽车充电速度
双转换在线式UPS的独特COTS应用
2022/2023年全国电子顺磁共振波谱学术研讨会成功举办
apu是什么?这个APU赛道分析报告讲透了国产APU厂商
升压型DC/DC转换器的PCB布局-PCB布局设计的重要性
关于MSP430单片机的大数组初始化
InGaAs单光子探测器的发展趋势
华为又一款实力机型,2K屏+海思麒麟1020+6000mAh
运营商将怎样打造5G安全网络?