26、一行数据中的多个NULL字段值在磁盘上怎么存储?
00 分钟
2022-8-26

26、一行数据中的多个NULL字段值在磁盘上怎么存储?

1、为什么一行数据里的NULL值不能直接存储?

之前我们已经学习了在数据库里一行数据中如果有VARCHAR(10)之类的变长字段,那么他的存储和读取会有什么问题,以及为了解决这个问题,为什么要给磁盘上存储的每一行数据都加入变长字段长度列表。
今天我们继续学习在磁盘上存储的一行数据里另外一块特殊的数据区域,就是NULL值列表。
这个所谓的NULL值列表,顾名思义,就是你一行数据里可能有的字段值是NULL,比如你有一个name字段,他是允许为NULL的,那么实际上在存储的时候,如果你没给他赋值,他这个字段的值就是NULL。
好,那么假设这个字段的NULL值我们在磁盘上存储的时候,就是按照 “NULL” 这么个字符串来存储,是不是很浪费存储空间?
本来他就是个NULL,说明什么值都没有,你还给他存个 “NULL” 字符串,你说这是干什么那?
所以实际在磁盘上存储数据的时候,一行数据里的NULL值是肯定不会直接按照字符串的方式存放在磁盘上浪费空间的。

2、NULL值是以二进制bit位来存储的

我们接着看,那么NULL值列表在磁盘上到底应该如何存储呢?
很简单,对所有的NULL值,不通过字符串在磁盘上存储,而是通过二进制的bit位来存储,一行数据里假设有多个字段的值都是NULL,那么这么多个字段的NULL,就会以bit位的形式存放在NULL值列表中。
现在我们来给大家举个例子,假设你有一个表,他的建表语句如下所示:
上面那个表就是一个假想出来的客户表,里面有5个字段,分别为name、address、gender、job、school,就代表了客户的姓名、地址、性别、工作以及学校。
其中有4个变长字段,还有一个定长字段,然后第一个name字段是声明了NOT NULL的,就是不能为NULL,其他4个字段都可能是NULL的。
那么现在我们来假设这个表里有如下一行数据,现在来看看,他在磁盘上是怎么来存储的:“jack NULL m NULL xx_school” ,他的5个字段里有两个字段都是NULL

3、结合小小案例来思考一行数据的磁盘存储格式

接着我们来思考上面那个表里的那行案例数据,在磁盘上应该如何存储呢,因为他有多个变长字段,还有多个字段允许为NULL。首先我们先回顾一下,一行数据在磁盘上的存储格式应该是下面这样的:
所以先看变长字段长度列表应该放什么东西,他一共有4个变长字段,那么按照我们上次说的,是不是应该按照逆序的顺序,先放school字段的长度,再放job、address、name几个字段的值长度?
说起来是这样,但是其实这里要区分一个问题,那就是如果这个变长字段的值是NULL,就不用在变长字段长度列表里存放他的值长度了,所以上面那行数据中,只有name和school两个变长字段是有值的,把他们的长度按照逆序放在变长字段长度列表中就可以了,如下所示:
接着来看NULL值列表,这个NULL值列表是这样存放的,你所有允许值为NULL的字段,注意,是允许值为NULL,不是说一定值就是NULL了,只要是允许你为NULL的字段,在这里每个字段都有一个二进制bit位的值,如果bit值是1说明是NULL,如果bit值是0说明不是NULL
比如上面4个字段都允许为NULL,每个人都会有一个bit位,这一行数据的值是 “jack NULL m NULL xx_school” ,然后其中2个字段是null,2个字段不是null,所以4个bit位应该是:1010
但是实际放在NULL值列表的时候,他是按逆序放的,所以在NULL值列表里,放的是:0101,整体这一行数据看着是下面这样的:
另外就是他实际NULL值列表存放的时候,不会说仅仅是4个bit位,他一般起码是8个bit位的倍数,如果不足8个bit位就高位补0,所以实际存放看起来是如下的:

4、磁盘上的一行数据到底如何读取出来的?

我们结合上面的磁盘上的数据存储格式来思考一下,一行数据到底是如何读取出来的呢?
再看上面的磁盘数据存储格式:
首先他必然要把变长字段长度列表和NULL值列表读取出来,通过综合分析一下,就知道有几个变长字段,哪几个变长字段是NULL,因为NULL值列表里谁是NULL谁不是NULL都一清二楚。
此时就可以从变长字段长度列表中解析出来不为NULL的变长字段的值长度,然后也知道哪几个字段是NULL的,此时根据这些信息,就可以从实际的列值存储区域里,把你每个字段的值读取出来了。
如果是变长字段的值,就按照他的值长度来读取,如果是NULL,就知道他是个NULL,没有值存储,如果是定长字段,就按照定长长度来读取,就这样可以完美的把你一行数据的值都读取出来了。

5、思考

为什么NULL值列表要按照二进制bit位的方式来存储?
他跟直接用NULL字符串的方式来存储,会有多少存储空间的差距呢?

评论