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

简介: 面试官: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的,所以实际开发中的记录都会有「变长字段长度列表」部分


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
7月前
|
存储 关系型数据库 MySQL
【免费动手教程上线】阿里云RDS MySQL推出大容量高性能存储:高性能本地盘(最高16TB存储空间)、高性能云盘(最高64TB存储空间)
阿里云RDS MySQL提供高性能本地盘与高性能云盘等存储方案,满足用户大容量、低延迟需求。高性能本地盘单盘最大16TB,IO延时微秒级;高性能云盘兼容ESSD特性,支持IO性能突发、BPE及16K原子写等能力。此外,阿里云还提供免费动手体验教程,帮助用户直观感受云数据库 RDS 存储性能表现。
|
10月前
|
存储 关系型数据库 MySQL
MySQL进阶突击系列(09)数据磁盘存储模型 | 一行数据怎么存?
文中详细介绍了MySQL数据库中一行数据在磁盘上的存储机制,包括表空间、段、区、页和行的具体结构,以及如何设计和优化行数据存储以提高性能。
|
存储 安全 Java
美团面试:String 为什么 不可变 ?(90%答错了,尼恩来一个绝世答案)
45岁老架构师尼恩分享Java面试心得,涵盖String不可变性、字符串常量池、面试技巧等内容。尼恩强调,掌握深层技术原理,如String不可变性的真正原因,可在面试中脱颖而出,赢得高薪Offer。此外,尼恩还提供了大量技术资源和面试指导,帮助求职者提升技术水平,顺利通过大厂面试。
|
存储 关系型数据库 MySQL
MySQL 字段类型探究:深入理解 Varchar(50) 与 Varchar(500)
在MySQL数据库中,`VARCHAR`类型是一种常用的字符串存储类型,它允许定义一个可变长度的字符串。然而,`VARCHAR(50)`和`VARCHAR(500)`之间的差异不仅仅是长度的不同,它们在存储和性能方面也有显著的区别。本文将深入探讨这两种字段类型的区别,以及它们在实际应用中的选择。
502 3
|
存储 关系型数据库 MySQL
MySQL 字段类型深度解析:VARCHAR(50) 与 VARCHAR(500) 的差异
在MySQL数据库中,`VARCHAR`类型是一种非常灵活的字符串存储类型,它允许存储可变长度的字符串。然而,`VARCHAR(50)`和`VARCHAR(500)`之间的差异不仅仅是长度的不同,它们在存储效率、性能和使用场景上也有所不同。本文将深入探讨这两种字段类型的区别及其对数据库设计的影响。
485 2
|
存储 关系型数据库 MySQL
PACS系统 中 dicom 文件在mysql 8.0 数据库中的 存储和读取(pydicom 库使用)
PACS系统 中 dicom 文件在mysql 8.0 数据库中的 存储和读取(pydicom 库使用)
405 2
|
存储 关系型数据库 MySQL
Key_Value 形式 存储_5级省市城乡划分代码 (mysql 8.0 实例)
本文介绍了如何使用MySQL8.0数据库中的Key_Value形式存储全国统计用区划代码和城乡划分代码(5级),包括导入数据、通过数学函数提取省市区信息,以及查询5级行政区划的详细数据。
198 0
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?

推荐镜像

更多