面试官:MySQL 中的 varchar 最多能存储多少个字符?大部分人都会答错。。。(2)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 面试官:MySQL 中的 varchar 最多能存储多少个字符?大部分人都会答错。。。(2)

3.3 varchar(M) 能存多少个字符,为什么提示最大16383?


首先要理解varchar(M)M是说字符个数,而不是字节。

为什么不能varchar(20000)之类的,是20000个字符放不下吗?


image.png

为什么提示只能最大16383个字符呢?这个数字是怎么算出来的?

这个我就得和你好好唠嗑了!


varchar是变长的,varchar(64) 能存放0~64个字符不等,并不一定是存了最大64个字符,谁知道这个类型到底存了几个字符呢?innodb设计的时候,就已经考虑到了,不过是用字节作为单位,后续我们可以根据对应字符集转变为字符来理解,innodb必须记录变长字段varchar真实占用的字节数L。前面说过了,innodb最多分配2个字节(16个bit位)的空间去记录这个L


InnoDB有它的一套规则,我们引入WML这几个符号:

  1. 假设某个字符集中「最多」需要W字节来表示一个字符
  • utf8mb4字符集中的W就是4
  • utf8字符集中W就是3
  • gbk字符集中的W就是2
  • ascii字符集中的W就是1
  1. 对于变长类型VARCHAR(M)来说,这种类型表示能存储最多M个字符(注意是字符不是字节) 所以这个类型能表示的字符串最多占用的字节数就是M × W
  2. 假设它实际存储的字符串占用的字节数是L


来看极限边界情况,innodb为了记录一下varchar真实存储多少个「字节」,最多分配2个字节的空间去记录,2个字节16个比特位,全部为1,最大能记录的数字是2^16-165535个,innodb最大能记录varchar占用的字节数就是65535个,utf8mb4字符集一个字符是最大是4个字节,65535 / 4 = 16383.75,只要varchar字符数不超过16383个,innodb就可以记录真实占用的长度L,再多就记录不了了!所以就能解释刚刚的图了,varchar(20000)不行,最大也就16383个字符


「但是!这里强调是有但是的!」


「行最大长度是65535字节」,行里面有很多东西,包括变长字段列表、NULL值列表、记录头信息。你得考虑该字段如果允许为NULLNULL值列表会占用一个字节(只要没超过8个字段),每一列字段的变长字段实际长度会花费1~2个字节,如果该字段的数据太大,会变成溢出列,该字段的数据会分成很多行存储(后面会讲,你可以看完NULL值列表和溢出列后再回来看这个例子)。所以即便提示16383个字符,你也绝对不可能存到16383


我做了个测试

create table t2 ( name varchar(16383))charset=utf8mb4;


image.png


不断往这个字段添加字符保存测试,最后发现,这些字符总长度到极限也就是48545字节。

image.png


这里48545个字节,再多一个字符就会报错,远不到65535字节,差了1W多字节。主要是因为溢出列的原因,数据分散在不同的行中,所以,很长的数据,建议往text类型考虑。这个现象可以看出,varchar(M)M很大,实际是达不到M这个边界值的。


下面说明一下规则(讲解中字符集用utf8mb4W=4)


规则一:如果允许存储的最大字节数M × W <= 255varchar占用的真实字节数L只分配1个字节来表示。」


有人说,允许存储的最大字节数M × W <= 255,即允许存储的最大字符数 <= ⌊255 / 4⌋ = 「63」个时,varchar占用的真实字节数L仅分配1个字节就能表示。这个结论正确吗?  显然错误,因为这里255 / 「4」,你怎么知道每个存储的一个字符是4个字节呢?难道全部存的emoji表情?不存字母汉字啥的?InnoDB在读记录的变长字段长度列表时先查看表结构,如果某个变长字段允许存储的最大字节数不大于255时,只用1个字节来表示真实数据占用的字节。


规则二:如果允许存储的最大字节数M × W > 255,则分为两种情况:

如果实际存储字节L <= 127varchar占用的真实字节数L仅分配1个字节就能表示。(⌊ … ⌋表示向下取整)


有人说,实际存储字节L <= 127,即「实际存储字符」 <= ⌊127 / 4⌋ = 「31」个时,varchar占用的真实字节数L仅分配1个字节就能表示。这个结论正确吗?  显然错误,因为这里127 / 「4」,你怎么知道实际存储的一个字符是4个字节呢?难道全部存的emoji表情?不存字母汉字啥的?



如果实际存储字节L > 127varchar占用的真实字节数L需要分配2个字节才能表示。


另外需要注意的是,变长字段列表只存储非NULL的列的长度。

表记录是这样的

image.png


对于第二条记录,c4列值为NULL,所以只存储c1c2列即可。

image.png

第一条记录的变长字段长度列表部分占用3字节空间,因为有c1c2c4列,且内容都很少,每列真实占用字节数用1个字节可以表示,加起来就是3个字节,第二条记录变长字段长度列表部分占用2字节。


当然,并不是所有记录都有这个「变长字段长度列表」部分,比方说表中「所有的列都不是变长的数据类型」或者 「所有列的值都是NULL 的话,这一部分就不需要有。实际业务开发中,几乎没有不使用varchar的,所以实际开发中的记录都会有「变长字段长度列表」部分


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7天前
|
SQL 关系型数据库 MySQL
Python与MySQL数据库交互:面试实战
【4月更文挑战第16天】本文介绍了Python与MySQL交互的面试重点,包括使用`mysql-connector-python`或`pymysql`连接数据库、执行SQL查询、异常处理、防止SQL注入、事务管理和ORM框架。易错点包括忘记关闭连接、忽视异常处理、硬编码SQL、忽略事务及过度依赖低效查询。通过理解这些问题和提供策略,可提升面试表现。
27 6
|
7天前
|
存储 Oracle 关系型数据库
【MySQL面试题pro版-12】
【MySQL面试题pro版-12】
14 0
|
7天前
|
SQL 关系型数据库 MySQL
【MySQL面试题pro版-10】
【MySQL面试题pro版-10】
13 1
|
7天前
|
缓存 关系型数据库 MySQL
【MySQL面试题pro版-9】
【MySQL面试题pro版-9】
20 1
|
7天前
|
存储 SQL 关系型数据库
【MySQL面试题pro版-8】
【MySQL面试题pro版-8】
12 0
|
7天前
|
存储 SQL 关系型数据库
【MySQL面试题pro版-7】
【MySQL面试题pro版-7】
18 0
|
7天前
|
存储 关系型数据库 MySQL
【MySQL面试题pro版-6】
【MySQL面试题pro版-6】
18 0
|
7天前
|
SQL 存储 关系型数据库
MySQL面试题系列-16
MySQL面试题系列-16
16 0
|
7天前
|
SQL 存储 关系型数据库
MySQL面试题系列-15
MySQL面试题系列-15
12 0
|
7天前
|
SQL 存储 关系型数据库
MySQL面试题系列-7
MySQL面试题系列-7
20 1