当前位置: 首页 > 后端技术 > Java

验证一个小问题

时间:2023-04-01 21:28:28 Java

我在之前的文章中提到了一个问题,网上很多文章也说了同样的话。日前,有人对这个问题提出了一些不同的意见,并做出了谨慎的态度。测试。问题是这样的:在COMPACT格式中,NULL值列表是否一定要占用一个字节的空间?对于这个问题,我的回答和网上很多回答是一样的。如果都是NOTNULL,则不会有NULL值列表,所以不会被占用,否则会被占用。今天,我们就来验证一下这个问题。存储空间先复习一下前面的知识。数据库中的一行记录在最终的磁盘文件中也是按行存储的。对于InnoDB,有四种行存储格式:REDUNDANT、COMPACT、DYNAMIC和COMPRESSED。InnoDB默认的行存储格式是COMPACT。存储格式如下,虚线不一定存在。变长字段长度列表:如果有多个字段,则倒序存储。我们只有一个领域,所以我们不考虑那么多。存储格式为十六进制。如果没有可变长度字段,则不需要这部分。NULL值列表:用来存储我们记录中的值为NULL的情况。如果有多个NULL值,同样倒序存储,并且必须是8位的整数倍。如果不够8位,高位补0。1表示NULL,0表示不为NULL。如果都是NOTNULL,那么这个是存在的,每多8个NULL就会多占用一个字节的空间。ROW_ID:一行记录的唯一标识,不指定主键时自动生成的ROW_ID作为主键。TRX_ID:交易ID。ROLL_PRT:回滚指针。最后是每列的值。为了弄清楚存储格式的问题,我做了一个表格来测试一下。该表中只有c1字段为NOTNULL,其他都可以为NULL。可变字段长度列表:c1和c3字段值的长度分别为1和2,所以转为十六进制后的长度为0x010x02,倒序为0x020x01。NULL值列表:因为有允许NULL的列,所以c2、c3、c4分别为010,倒序后相同。同时高位补0补8位,结果为00000010,其他字段我们暂且不管。最后第一条记录的结果是。当然这里不考虑编码后的结果。这是一个完整数据行的格式。反之,如果我们把所有字段都设置为NOTNULL,插入一条数据a,bb,ccc,dddd,存储格式应该是这样的:测试中有点问题,首先我看到了测试和阿里数据库月报中的描述。从这段代码可以看出前面的猜想,即不是Null标志只占1个字节==,而是以8为单位,如果有8个null字段,就会多1个字节。占1个字节,高位补0,他的意思是无论如何都要占一个字节,但是看了他的测试发现他的表允许NULL,所以他的测试不能说明我们要验证的问题。按照网上大佬给的方案,建表,然后插入测试数据。数据库中有NULL值。创建表测试(c1VARCHAR(32),c2VARCHAR(32),c3VARCHAR(32),c4VARCHAR(32))ENGINE=INNODBrow_format=compact;使用命令SHOWVARIABLESLIKE'datadir'查找ibd文件位置。使用命令将ibd文件转换为txt文件。hexdump-C-vtest.ibd>/Users/irving/test-null.txt打开文件并找到supremum部分。不看那么多,只看一部分:03020201就是上面说的变长字段长度列表,以为我们有4个字段,所以4个字节。00是NULL标志。0000100025是数据的前5个字节。这绝对没问题。然后重新创建一个表。此时字段全部为NOTNULL,然后再次执行命令。创建表测试(c1VARCHAR(32)不为空,c2VARCHAR(32)不为空,c3VARCHAR(32)不为空,c4VARCHAR(32)不为空)ENGINE=INNODBrow_format=compact;获取另一个ibd文件。其实很清楚,通过对比就能发现问题。此时,NULL值列表没有标志位。SO,这个测试结果证明,如果有任何NULL值,NULL值列表至少占用一个字节的空间,以后每多8个NULL值就多占用一个字节。如果它们都是NOTNULL,则不会有NULL值列表标记,不占用空间。巨人的肩膀:http://mysql.taobao.org/month...https://www.cnblogs.com/zhouj...