验证一个小小的问题

在之前的文章提到过一个问题,而且网上很多文章也是这么说的,前几天有人对这个问题提出了一点不同的意见,抱着谨慎的态度做了一个测试。

问题是这样的:COMPACT格式下,NULL值列表是否一定会占用一个字节的空间?

对于这个问题,我的回答和网上很多回答是一样的,如果都是NOT NULL就不会有NULL值列表,所以不会占用,反之则会占用。

今天,就对这个问题做一个验证。

存储空间

先回顾一下之前的知识。

数据库中的一行记录在最终磁盘文件中也是以行的方式来存储的,对于InnoDB来说,有4种行存储格式:REDUNDANTCOMPACTDYNAMICCOMPRESSED

InnoDB的默认行存储格式是COMPACT,存储格式如下所示,虚线部分代表可能不一定会存在。

变长字段长度列表:有多个字段则以逆序存储,我们只有一个字段所有不考虑那么多,存储格式是16进制,如果没有变长字段就不需要这一部分了。

NULL值列表:用来存储我们记录中值为NULL的情况,如果存在多个NULL值那么也是逆序存储,并且必须是8bit的整数倍,如果不够8bit,则高位补0。1代表是NULL,0代表不是NULL。如果都是NOT NULL那么这个就存在了,每多8个NULL会多占用一个字节的空间。

ROW_ID:一行记录的唯一标志,没有指定主键的时候自动生成的ROW_ID作为主键。

TRX_ID:事务ID。

ROLL_PRT:回滚指针。

最后就是每列的值。

为了说明清楚这个存储格式的问题,我弄张表来测试,这张表只有c1字段是NOT NULL,其他都是可以为NULL的。

可变字段长度列表c1c3字段值长度分别为1和2,所以长度转换为16进制是0x01 0x02,逆序之后就是0x02 0x01

NULL值列表:因为存在允许为NULL的列,所以c2,c3,c4分别为010,逆序之后还是一样,同时高位补0满8位,结果是00000010

其他字段我们暂时不管他,最后第一条记录的结果就是,当然这里我们就不考虑编码之后的结果了。

这样就是一个完整的数据行数据的格式,反之,如果我们把所有字段都设置为NOT NULL,并且插入一条数据a,bb,ccc,dddd的话,存储格式应该这样:

测试

这里存在一点点小问题,首先我看到了阿里的数据库月报中的测试和描述。

从这段代码看出之前的猜想,也就是并不是Null标志位只固定占用1个字节==,而是以8为单位,满8个null字段就多1个字节,不满8个也占用1个字节,高位用0补齐

他的意思是无论如何都会占用一个字节,但是看了他的测试,发现他的表是允许NULL的,所以他的这个测试无法说明我们要验证的问题。

按照网上大佬给出的方案,创建表,然后插入测试数据,数据库中存在NULL值。

 CREATE TABLE test ( c1 VARCHAR ( 32 ),
   c2 VARCHAR ( 32 ),
   c3 VARCHAR ( 32 ),
   c4 VARCHAR ( 32 ) ) ENGINE = INNODB row_format = compact;

使用命令SHOW VARIABLES LIKE 'datadir'找到 ibd 文件位置。

使用命令转换 ibd 文件为 txt 文件。

hexdump -C -v test.ibd > /Users/irving/test-null.txt

打开文件找到 supremum 部分。

不用看那么多,就看一部分:

03 02 02 01 是上面说的变长字段长度列表,以为我们有4个字段,所以4个字节。

00 就是NULL标志位

00 00 10 00 25 是数据头5个字节

这个肯定没有问题,然后再次创建一张表,这时候字段都是NOT NULL,然后再次执行命令。

 CREATE TABLE test ( c1 VARCHAR ( 32 ) NOT NULL,
   c2 VARCHAR ( 32 ) NOT NULL,
   c3 VARCHAR ( 32 ) NOT NULL,
   c4 VARCHAR ( 32 ) NOT NULL ) ENGINE = INNODB row_format = compact;

拿到另外一个 ibd 文件。

对比其实很清楚能发现问题,这时候已经没有了NULL值列表的标志位了。

SO,这个测试结果证明,如果存在任意NULL值,NULL值列表至少占用一个字节的空间,以后每多8个NULL值多占用一个字节,如果都是NOT NULL,则不会存在NULL值列表标记,不占用空间。

巨人的肩膀:

http://mysql.taobao.org/month...

https://www.cnblogs.com/zhouj...


192 声望
68 粉丝
0 条评论
推荐阅读
RabbitMQ、RocketMQ、Kafka延迟队列实现
延迟队列在实际项目中有非常多的应用场景,最常见的比如订单未支付,超时取消订单,在创建订单的时候发送一条延迟消息,达到延迟时间之后消费者收到消息,如果订单没有支付的话,那么就取消订单。

艾小仙阅读 972

Java12的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft63阅读 12k

Java8的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft32阅读 24.7k评论 1

一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go35阅读 2.6k评论 1

封面图
Java11的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft28阅读 15.5k评论 3

Java5的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft13阅读 20.5k

Java9的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft20阅读 14.6k

192 声望
68 粉丝
宣传栏