验证一个小小的问题

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

问题是这样的: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/monthly/2016/08/07/
https://www.cnblogs.com/zhoujinyi/archive/2012/10/17/2726462.html

Original: https://www.cnblogs.com/ilovejaney/p/16662461.html
Author: 艾小仙
Title: 验证一个小小的问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/608826/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 部署-jenkins发布项目到linux环境

    使用openSSH的方式 如果jenkins跟服务器不在同一台服务器上,这时候我们可以借助ssh的方式将打包好的jar包发送到远程服务器,然后以后台的方式运行程序。 安装publi…

    Java 2023年6月7日
    091
  • 部署-docker安装jenkins

    什么是jenkins jenkins是基于java开发的一种持续集成的工具,提供了web界面来进行jenkins的配置与管理。jenkins通常与版本管理工具一起使用,可以实现程序…

    Java 2023年6月7日
    084
  • java list遍历添加元素_【转】:java遍历List时动态添加和删除元素

    遍历元素最常见的三种方法: // 1.最普通的一种方式 for(int i = 0;i < size;i++) //2.for each方式 for(BEAN b: BEAN…

    Java 2023年5月29日
    071
  • 译文《全新首发JDK 16全部新特性》

    封面:洛小汐 译者:潘潘 JDK 8 的新特性都还没摸透,JDK 16 的新特性就提着刀来了。 郑重申明:第一次冒险翻译专业领域的文献,可想而知,效果特别糟糕。一般翻译文献特别是 …

    Java 2023年6月13日
    052
  • JDK各个版本发布时间

    JDK各个版本发布时间 Java 8是于2014年3月14号发布。从Java 8开始开发代号已经弃用了,所以从Java 8之后已经没有官方的开发代号了。Java 8u201/202…

    Java 2023年5月30日
    0105
  • 软件工程 结构化设计方法 第3篇随笔

    * 调用:模块间的一种关系,模块A为了完成其任务必须依赖其他模块 ​ ——————> Original: https://www.cnblogs.com/shuisanya/…

    Java 2023年6月16日
    0100
  • java内存模型&jvm内存模型

    JVM内存模型JVM内存模式主要分为:程序计数器、JAVA虚拟机栈、本地方法栈、堆和方法区,其中JDK1.8之前方法区的实现为永生代,而JDK1.8之后方法区的实现转为元空间。各个…

    Java 2023年6月13日
    089
  • POSIX 线程的创建与退出

    创建线程: 退出线程: 使用多线程,首先就需要创建一个新线程。那么线程是如何被创建的呢,是用下面这个函数创建的。 创建函数的四个参数的意义分别如下: 返回值:如果函数执行成功,则返…

    Java 2023年5月30日
    082
  • java设计模式之七大原则

    以下为本人的学习笔记 1.设计模式的目的 编写软件过程中,程序员面临着来自耦合性,内聚性和可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让程序(软件)具有更好的 …

    Java 2023年6月15日
    0103
  • MyBatis 持久化原理的学习笔记

    1.什么是MyBatis ,MyBatis 的用途是什么,为什么要用 MyBatis ? 佛语:我本求心不求佛,了知三界空无物,若欲求佛但求心,只这心心心是佛 Original: …

    Java 2023年5月30日
    0102
  • 动态调整日志级别思路&实现

    引言 上篇文章 性能调优——小小的 log 大大的坑 已将详细的介绍了高并发下,不正确的使用日志姿势,可能会导致服务性能急剧下降问题。文末也给各位留下了解决方案——日志级别动态调整…

    Java 2023年6月15日
    0121
  • 关于 .NET 与 JAVA 在 JIT 编译上的一些差异

    最近因为公司的一些原因,我也开始学习一些 JAVA 的知识。虽然我一直是以 .NET 语言为主的程序员,但是我并不排斥任何其它语言。在此并不讨论 JAVA .NET 的好坏,仅仅是…

    Java 2023年5月29日
    096
  • Centos7 安装Git 版本控制

    Centos7 安装Git 版本控制 最近开始认真学习一遍git ,虽然已经使用git 蛮久了,但是其实对这个的了解 可能也就是 使用层面了。。提供一个 git 官网 zh (中文…

    Java 2023年6月9日
    095
  • Mybatis 分页:Pagehelper + 拦截器实现

    一、分页插件 Pagehelper PageHelper是 Mybatis的一个分页插件,非常好用! com.github.pagehelper pagehelper-spring…

    Java 2023年6月5日
    097
  • Java通过PriorityQueue构建大顶堆和小顶堆

    Comparator comparator = Comparator.comparing(Obj::getValue); 小顶堆: PriorityQueue minHeap = …

    Java 2023年5月29日
    078
  • Spring Boot:整合JdbcTemplate

    综合概述 Spring对数据库的操作在jdbc上面做了更深层次的封装,而JdbcTemplate便是Spring提供的一个操作数据库的便捷工具。我们可以借助JdbcTemplate…

    Java 2023年5月30日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球