(十二)大白话对于VARCHAR这种变长字段,在磁盘上到底是如何存储的?

1、一行数据在磁盘上存储的时候,包含哪些东西?

上一讲我们已经告诉了大家,一行数据在磁盘上存储的时候,其实不仅仅是包含我们想象的那一点数据,他还包含了很多其他的信息,之前告诉大家,一行数据的存储格式大致如下所示。
在这里插入图片描述
说白了,就是除了每一个字段的值以外,他还包含了一些额外的信息,这些额外的信息就是用来描述这一行数据的。今天我们就详细给大家说说这些额外的信息里都是放了什么东西。

2、变长字段在磁盘中是怎么存储的?

大家都知道,在MySQL里有一些字段的长度是变长的,是不固定的,比如VARCHAR(10)之类的这种类型的字段,实际上他里面存放的字符串的长度是不固定的,有可能是“hello”这么一个字符串,也可能是“a”这么一个字符串。
在这里插入图片描述
好,那么现在我们来假设一下,现在有一行数据,他的几个字段的类型为
VRACHAR(10),CHAR(1),CHAR(1)
,那么他第一个字段是VARCHAR(10),这个长度是可能变化的,所以这一行数据可能就是类似于:hello a a,这样子,第一个字段的值是“hello”,后面两个字段的值都是一个字符,就是一个a;

然后另外一行数据,同样也是这几个字段,他的第一个字段的值可能是“hi”,后面两个字段也是“a”,所以这一行数据可能是类似于:hi a a。一共三个字段,第一个字段的长度是是不固定的,后面两个字段的长度都是固定的1个字符,如下图所示。
在这里插入图片描述
想必这个道理大家都能理解吧?

那么现在,我们来假设你把上述两条数据写入了一个磁盘文件里,两行数据是挨在一起的,那么这个时候在一个磁盘文件里可能有下面的两行数据:

hello a a hi a a

大家可以看到,如上图所示,两行数据在底层磁盘文件里是不是挨着存储的?

没错!其实平时你看到的表里的很多行数据,最终落地到磁盘里的时候,都是上面那种样子的,一大坨数据放在一个磁盘文件里都挨着存储的

3、存储在磁盘文件里的变长字段,为什么难以读取?

现在我们来继续思考一个问题,假设现在我们要读取上面的磁盘文件里的数据,要读取出来hello a a这一行数据。那你觉得是那么容易的吗?

当然不是了!这个过程比你想象的可能要困难一些。

假如现在你要读取hello a a这行数据,

  • 第一个问题就是,从这个磁盘文件里读取的时候,到底哪些内容是一行数据?我不知道啊!

  • 因为这个表里的第一个字段是VARCHAR(10)类型的,第一个字段的长度是多少我们是不知道的!

所以有可能你读取出来**“hello a a hi”是一行数据,也可能是你读取出来“hello a”**是一行数据,你在不知道一行数据的每个字段到底是多少长度的情况下,胡乱的去读取是不现实的,根本不知道磁盘文件里混成一坨的数据里,哪些数据是你要读取的一行?
在这里插入图片描述

4、引入变长字段的长度列表,解决一行数据的读取问题

所以说才要在存储每一行数据的时候,都保存一下他的变长字段的长度列表,这样才能解决一行数据的读取问题。

  • 也就是说,你在存储“hello a a”这行数据的时候,要带上一些额外的附加信息,比如第一块就是他里面的变长字段的长度列表

  • 也就是说,这个hello是VARCHAR(10)类型的变长字段的值,那么这个“hello”字段值的长度到底是多少?

我们看到“hello”的长度是5,十六进制就是0x05,所以此时会在“hello a a”前面补充一些额外信息,首先就是变长字段的长度列表,你会看到这行数据在磁盘文件里存储的时候,其实是类似如下的格式:0x05 null值列表 数据头 hello a a,如下图所示。
在这里插入图片描述
你这行数据存储的时候应该是如上所示的!

这个时候假设你有两行数据,还有一行数据可能就是:0x02 null值列表 数据头 hi a a,两行数据放在一起存储在磁盘文件里,看起来是如下所示的:

在这里插入图片描述

5、引入变长字段长度列表后,如何解决变长字段的读取问题?

所以假设此时你要读取**“hello a a”这行数据,你首先会知道这个表里的三个字段的类型是VARCHAR(10) CHAR(1) CHAR(1)**,那么此时你先要读取第一个字段的值,那么第一个字段是变长的,到底他的实际长度是多少呢?

此时你会发现第一行数据的开头有一个变长字段的长度列表,里面会读取到一个0x05这个十六进制的数字,发现第一个变长字段的长度是5,于是按照长度为5,读取出来第一个字段的值,就是**“hello”**

接着你知道后续两个字段都是CHAR(1),长度都是固定的1个字符,于是此时就依次按照长度为1读取出来后续两个字段的值,分别是**“a”“a”,于是最终你会读取出来“hello a a”**这一行数据!

接着假设你要读取第二行数据,你先看一下第二行数据后的变长字段长度列表,发现他第一个变长字段的长度是0x02,于是就读取长度为2的字段值,就是**“hi”,再读取两个长度固定为1的字符值,都是“a”,此时读取出来“hi a a”**这行数据。

6、如果有多个变长字段,如何存放他们的长度?

接着我们假设,如果说有多个变长字段,如何存放他们的长度?

比如一行数据有VARCHAR(10) VARCHAR(5) VARCHAR(20) CHAR(1) CHAR(1),一共5个字段,其中三个是变长字段,此时假设一行数据是这样的:hello hi hao a a,如下图所示。

在这里插入图片描述
此时在磁盘中存储的,必须在他开头的变长字段长度列表中存储几个变长字段的长度,一定要注意一点,他这里是逆序存储的!

也就是说先存放**VARCHAR(20)这个字段的长度,然后存放VARCHAR(5)这个字段的长度,最后存放VARCHAR(10)**这个字段的长度。

现在hello hi hao三个字段的长度分别是0x05 0x02 0x03,但是实际存放在变长字段长度列表的时候,是逆序放的,所以一行数据实际存储可能是下面这样的:
在这里插入图片描述

7、今日思考题

今天让大家思考一个问题,为什么MySQL在把一行一行的数据存储在磁盘上的时候,要采取这种0x05 null值列表 数据头 hello a a 0x02 null值列表 数据头 hi a a很多行数据都紧紧挨在一起的方式?

为什么MySQL不能用Java里面的序列化的那种方式?
把很多行的数据做成一个大的对象,然后给他序列化一下写入到磁盘文件里,从磁盘里读取的时候压根儿不用care什么行存储格式,直接反序列化一下,把数据就可以从磁盘文件里拿回来了。

请大家思考一下,MySQL用这种数据紧凑挨在一起的方式来存储数据,到底有什么好处?

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值