一行数据中的多个NULL字段值在磁盘上怎么存储?
在数据库里一行数据中如果有VARCHAR(10)之类的变长字段,那么他的存储和读取会有什么问题,以及为了解决这个问题,为什么要给磁盘上存储的每一行数据都加入变长字段长度列表。
接下来研究下在磁盘上存储的一行数据里另外一块特殊的数据区域,就是NULL值列表。
这个所谓的NULL值列表,顾名思义,说的就是你一行数据里可能有的字段值是NULL。
比如你有一个name字段,他是允许为NULL的,那么实际上在存储的时候,如果你没给他赋值,他这个字段的值就是NULL。 那么假设这个字段的NULL值我们在磁盘上存储的时候,就是按照“NULL”这么个字符串来存储,是不是很浪费 存储空间? 本来他就是个NULL,说明什么值都没有,你还给他存个“NULL”字符串,你说你这是干什么呢?
所以实际在磁盘上存储数据的时候,一行数据里的NULL值是肯定不会直接按照字符串的方式存放在磁盘上浪费空间的。
2、NULL值是以二进制bit位来存储的
那NULL值列表在磁盘上到底应该如何存储呢?很简单,对所有的NULL值,不通过字符串在磁盘上存储,而是通过二进制的bit位来存储,一行数据里假设有多个字段的值都是NULL,那么这多个字段的NULL,就会以bit位的形式存放在NULL值列表中。
现在我们来给大家举个例子,假设你有一个表,建表语句如下:
CREATE TABLE customer (
name VARCHAR(10) NOT NULL,
address VARCHAR(20),
gender CHAR(1),
job VARCHAR(30),
school VARCHAR(50)
) ROW_FORMAT=COMPACT;
上面表就是一个假想出来的客户表,里面有5个字段,分别为name、address、genderjob、school,就代表了客户的姓名、地址、性别、工作以及学校。 其中有4个变长字段,还有一个定长字段,然后第一个name字段是声明了NOT NULL的,就是不能为NULL,其他4个字段都可能是NULL的。
我们来假设这个表里有如下一行数据,他在磁盘上是怎么来存储的:“jack NULL m NULL xx_school”,他的5个字段里有两个字段都是NULL。
3、结合小小案例来思考一行数据的磁盘存储格式
来思考上面那个表里的那行数据,在磁盘上应该如何存储呢,因为他有多个变长字段,还有多个字段允许为NULL。一行数据在磁盘上的存储格式应该是下面这样的:
变长字段长度列表 NULL值列表 头信息 column1=value1 column2=value2 ... columnN=valueN
所以先看变长字段长度列表应该放什么东西,他一共有4个变长字段,那么按照我们上次说的,是不是应该按照逆序的顺序,先放school字段的长度,再放job、address、name几个字段的值长度?
说起来是这样,但是其实这里要区分一个问题,那就是如果这个变长字段的值是NULL,就不用在变长字段长度列表里存放他的值长度了,所以在上面那行数据中,只有name和school两个变长字段是有值的,把他们的长度按照逆序放在变长字段长度列表中就可以了,如下所示:
0x09 0x04 NULL值列表 头信息 column1=value1 column2=value2 ... columnN=valueN
接着来看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,整体这一行数据看着是下面这样的
0x09 0x04 0101 头信息 column1=value1 column2=value2 ... columnN=valueN
另外就是他实际NULL值列表存放的时候,不会说仅仅是4个bit位,他一般起码是8个bit位的倍数,如果不足8个bit位就高位补0,所以实际存放看起来是如下的:
0x09 0x04 00000101 头信息 column1=value1 column2=value2 ... columnN=valueN
4、磁盘上的一行数据到底如何读取出来的?
结合上面的磁盘上的数据存储格式来思考一下,一行数据到底是如何读取出来的呢? 再看上面的磁盘数据存储格式:
0x09 0x04 00000101 头信息 column1=value1 column2=value2 ... columnN=valueN
首先他必然要把变长字段长度列表和NULL值列表读取出来,有哪几个变长字段,哪几个变长字段是NULL,因为NULL值列表里谁是NULL谁不是NULL都一清二楚。
此时就可以从变长字段长度列表中解析出来不为NULL的变长字段的值长度,然后也知道哪几个字段是NULL的,此时根据这些信息,就可以从实际的列值存储区域里,把你每个字段的值读取出来了。
- 如果是变长字段的值,就按照他的值长度来读取,
- 如果是NULL,就知道他是个NULL,没有值存储,
- 如果是定长字段,就按照定长长度来读取,
这样就可以完美的把你一行数据的值都读取出来了!
思考
为什么NULL值列表要按照二进制bit位的方式来存储? 他跟直接用NULL字符串的方式来存储,会有多少存储空间的差距呢?