• InnoDB数据页结构(3)之记录头信息分析


    InnoDB数据页结构之记录头信息分析

    在之前的文章中有分析得到记录头每个部分的二进制值如下所示

    对应表数据如下所示

    +----+------+------+
    | c1 | c2   | c3   |
    +----+------+------+
    |  1 |  100 | aaaa |
    |  2 |  200 | bbbb |
    |  3 |  300 | cccc |
    |  4 |  400 | dddd |
    +----+------+------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    下面来具体分析下这些值的具体含义(当然不包含预留位1和预留位2)

    delete_mask

    delete_mask是一个删除标识当该值为0时表示正常数据,为1时表示已删除数据,可以做如下实验

    删除c1=1的列,也就是第一列

    mysql> delete from page_demo where c1=1;
    Query OK, 1 row affected (0.01 sec)
    -- 再次查询,只剩三列
    mysql> select * from page_demo;
    +----+------+------+
    | c1 | c2   | c3   |
    +----+------+------+
    |  2 |  200 | bbbb |
    |  3 |  300 | cccc |
    |  4 |  400 | dddd |
    +----+------+------+
    3 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    同时再次获取page_demo的ibd文件,同时通过hexdump转换为16进制信息如下所示

    其中被删除的记录头信息如下所示

    十六进制:20 00 10 00 00
    二进制 :00100000 00000000 00010000 00000000 00000000
    
    • 1
    • 2

    到这里我们可以对比得出,当我们执行delete语句删除数据时,其实仅仅是将该条记录的记录头信息中的delete_mask由0改为了1相当于打了一个删除标识,并没有立即在磁盘中将该条数据删除,因为移除这些空间还需要将空间重新整理消耗性能,这些已经删除的记录会形成一个垃圾链表,这个链表占用的空间被称为可重用空间。

    min_rec_mask

    这里先简单理解为B+树的每层非叶子节点中的最小记录将会采用该字段标记。

    heap_no

    这个属性表示这条记录在该页中的位置,从上图列表中可以看到表中对应的四条数据heap_no的值依次为2、3、4、5这时就有疑问了,为什么是从2开头呢?难道前面还有隐藏记录?这就要聊到最小记录infimum和最大记录supremum被称为伪记录或者虚拟记录,这两条记录十分简单就是由5个字节的记录头以及8个字节的固定部分构成如下所示

    根据page_demo的ibd文件,如下所示

    ....省略记录
    0000c050  00 02 00 f2 00 00 00 68  00 00 00 02 00 32 01 00  |.......h.....2..|
    0000c060  02 00 1c 69 6e 66 69 6d  75 6d 00 05 00 0b 00 00  |...infimum......|
    0000c070  73 75 70 72 65 6d 75 6d  04 00 00 00 10 00 20 80  |supremum...... .|
    ....省略记录
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可得到infimum和supremum的记录头信息

    infimum :01 00 02 00 1c
    supremum:05 00 0b 00 00
    
    • 1
    • 2

    将上面十六进制数据转为二进制如下

    infimum :00000001 00000000 00000002 00000000 00011100
    supremum:00000005 00000000 00001011 00000000 00000000
    
    • 1
    • 2

    那么最小记录和最大记录的记录头信息拆分如下

    从这里就可以看出最小记录和最大记录的为每个页0和1的位置,业务数据从2开始。

    record_type

    从上面测试表page_demo的测试列记录头信息和伪记录(最小记录和最大记录)可以看出record_type有三种值0、2、3不过从这三个值也很容易推理出还有一个类型值为1,分别代表什么意思呢?

    • 0:业务数据,普通记录。

    • 1:B+树的非叶子节点(本文暂时还没用到)。

    • 2:最小记录。

    • 3:最大记录。

    next_record

    当前记录的真实数据到下一条记录的真实数据的地址偏移量,这里就可以简单理解为链表,不过需要注意的是这个链表的顺序并不是指插入顺序,而是根据表的主键由小到大排列,这里也包含最小记录和最大记录,如下所示

    无论数据如何操作数据页都会维护一个单链表,当有数据删除时,该条数据的next_record将会置为0表示没有下一条记录了。

    n_owned

    我们知道所有的记录由next_record连接起来形成一个链表后,思考一个问题,链表的痛点是什么?无非是查找效率低,那么InnoDB为什么还要使用链表呢?显然是对链表做了优化的,为了高效查找InnoDB将包括最小记录infimum和最大记录supremum在内的正常记录分组(不包含已删除记录),而每个组最大的那条记录的n_owned字段则表示每个组的记录数量,所以测试表中包含了两个组

    • 第一组:最小记录infimum所在记录,只有自身一条记录。

    • 第二组:最大记录supremum所在记录,自身一条记录和四条业务记录所以n_owned才为5。

  • 相关阅读:
    PostgreSQL 命令行工具介绍
    Elasticsearch7.17 五 :ES读写原理、分片设计和性能优化
    01.02 环境搭建详细介绍
    技术分享 | 接口自动化测试如何进行认证?
    AQS原理解析
    云原生2.0网关API标准发展趋势
    axios+vue 请求时如何携带cookie
    电视剧里的代码真能运行吗?
    Sun Solaris 修改IP地址或者主机名
    MYSQL 数据库对比 工具类
  • 原文地址:https://blog.csdn.net/zzf1233/article/details/126295083