开发者

MySQL之InnoDB存储引擎中的页用法解读

开发者 https://www.devze.com 2025-06-28 09:10 出处:网络 作者: 在成都搬砖的鸭鸭
目录1、背景2、页的组成3、各部分讲解【1】文件头部【2】页头部【3】最小记录和最大记录【4】行记录【5】空闲空间【6】页目录【7】文件尾部4、总结1、背景
目录
  • 1、背景
  • 2、页的组成
  • 3、各部分讲解
    • 【1】文件头部
    • 【2】页头部
    • 【3】最小记录和最大记录
    • 【4】行记录
    • 【5】空闲空间
    • 【6】页目录
    • 【7】文件尾部
  • 4、总结

    1、背景

    mysql中存储数据是存储引擎干的事,存储引擎存储数据的基本单位是页,我们往数据库插入表中的一条条记录就是存储在页上的,今天我们就来熟悉一下页上面有哪些内容。

    2、页的组成

    页由7部分组成,先大概字面意思理解一下,后面再各部分详细讲php解,组成图如下:

    MySQL之InnoDB存储引擎中的页用法解读

    表格解释如下:

    名称字节大小描述
    文件头部38页的通用信息
    页头部56页的专有信息
    最小记录和最大记录262个固定的行记录
    行记录不固定存放用户数据
    空闲空间不固定未使用存放用户数据的空间
    页目录不固定存放槽
    文件尾部8校验页面是否完整

    3、各部分讲解

    【1】文件头部

    文件头部38个字节由8个部分组成,看表理解:

    名称字节大小描述
    FIL_PAGE_SPACE_OR_CHKSUM4表空间id或校验和
    FIL_PAGE_OFFSET4页号,当前页的唯一标识
    FIL_PAGE_PREV4上一个页号唯一标识
    FIL_PAGE_NEXT4下一个页号唯一标识
    FIL_PAGE_LSN8该页最后一次修改对应的redo日志序号
    FIL_PAGE_TYPE2页类型
    FIL_PAGE_FILE_FLUSH_LSH8该页被刷到磁盘的redo日志序号
    FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID4归档日志编号或页属于哪个表空间

    1、本文是在FIL_PAGE_TYPE为数据页的基础上进行讲解

    2、FIL_PAGE_SPACE_OR_CHKSUM对于数据页的类型含义为校验和,用来和文件尾部的校验和进行对比

    【2】页头部

    页头部的56个字节由14个部分组成,看表理解:

    名称字节大小描述
    PAGE_N_DIR_SLOTS2页目录中存储槽的数量
    PAGE_HEAP_TOP2页中空闲空间地址
    PAGE_N_HEAP2未标记删除用户记录 + 已标记删除用户记录 + 最小记录 + 最大记录
    PAGE_FREE2第1条标记为已删除的用户记录地址
    PAGE_GARBAGE2所有标记为已删除记录占用的字节数
    PAGE_LAST_INSERT2最后一条用户记录插入位置
    PAGE_DIRECTION2最后一条用户记录插入方向,主键/unique健/隐藏列唯一键比上一条大就为右,反之为左
    PAGE_N_RECS2未标记为删除的用户记录数
    PAGE_MAX_TRX_ID8修改当前页的最新事务id
    PAGE_LEVEL2当前页在B+树中的层级
    PAGE_INDEX_ID8当前页属于的索引ID
    PAGE_BTR_SEG_LEAF10B+树叶子段的头部信息
    PAGE_BTR_SEG_TOP10B+树非叶子段的头部信息

    【3】最小记录和最大记录

    最小记录和最大记录2条记录是页中固定就存在的,最小记录和最大记录都是由5字节头部信息+8字节数据组成,所以它们总共占用空间26字节,最小记录数据部分固定为’infimum’,最大记录数据部分固定为’supremum’, 在讲它之前我们先了解一下Compact行格式中头部信息用5字节来存储的行记录信息,其组成部分如下:

    名称位大小描述
    预留位1未使用
    预留位1未使用
    delete_mask10-记录未删除,1-记录已删除
    min_rec_mask1B+树非叶子节点中的最小记录
    n_owned4当前记录在记录组里拥有记录数
    heap_no13当前记录在记录堆中的位置
    record_type3记录类型,0-普通记录,1-B+数非叶子节点记录,2-最小记录,3-最大记录
    next_record16指向下一条未被删除的记录

    当页中没有任何用户记录时,最小记录和最大记录可以如图表示:

    MySQL之InnoDB存储引擎中的页用法解读

    最小记录中的n_owned为1表示以最小记录结尾的分组记录中只有一条记录,这条记录就是最小记录本身,最小记录的next_record为13代表最小记录数据部分与下一条数据部分的偏移量,所以上图箭头指向最大记录的固定数据部分,13字节大小是这样计算的: 最小记录固定数据部分(8) + 最大记录头部信息(5)

    next_record之所以指向下一条记录的数据部分是因为:对于用户记录,指向位置往左的头部信息中还有逆序的长度列表、逆序的是否为NULL列表,往右就是数据部分。

    最大记录中的n_owned为1表示以最大记录结尾的分组记录中只有一条记录,这条记录就是最大记录本身,最大记录的next_record为0代表没有下一条记录,它就是最后一条记录。

    n_owned数有这样的定义:

    • 1、最小记录所在分组记录数最多只能有1条。
    • 2、最大记录所在分组记录数范围为1~8条。
    • 3、用户记录所在分组记录数范围为4~8条。

    【4】行记录

    行记录讲解需要根据数据来进行理解了,我们先创建一张表如下:

    CRphpEATE TABLE testwww.devze.com
    (
        id INT AUTO_INCREMENT PRIMARY KEY,
        str VARCHAR(255) NOT NULL DEFAULT ''
    ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
    

    插入3条记录:

    INSERT INTO test (str)
    VALUES ('AAA'),
           ('BBB'),
           ('CCC');
    

    查看记录:

    mysql [xxx]> select * from test;
    +----+-----+
    | id | str |
    +----+-----+
    |  1 | AAA |
    |  2 | BBB |
    |  3 | CCC |
    +----+-----+
    3 rows in set (0.001 sec)
    

    此时插入的3条记录和最小最大记录可以如图表示:

    MySQL之InnoDB存储引擎中的页用法解读

    可以看到所有记录通过nex_record的偏移量组成了一个链表,删除其中某条记录,就会把该条记录的delete_mask设置为1,next_record设置为0,但是记录依然存在,只是标记为了删除,这是为了后面插入新数据时可以对这部分空间进行复用,如图:

    MySQL之InnoDB存储引擎中的页用法解读

    因为是第1条标记删除的记录,也会在页头部记录这条记录的地址,如python果有多条删除记录,它们之间也会组成一个链表。

    【5】空闲空间

    空闲空间就是给行记录使用的,行记录空间增加,空闲空间就减少。

    【6】页目录

    页目录就是用来存储槽的,槽就是一组用户记录中,相对页起始位置偏移量最大的一条记录, 这条记录数据部分相对页起始位置的偏移量就作为槽,槽对应的记录中的n_owned属性就代表这条记录对应的用户组内有多少条记录,槽与记录关系可以如图表示:

    MySQL之InnoDB存储引擎中的页用法解读

    最大记录看起来虽然是在最后面,起始它是和最小记录挨着的,所以后面记录增加导致分组产生新增槽时相对页起始位置的偏移量要比槽1大。

    在讲最小记录和最大记录时讲过分组记录的约束,根据这个约束行记录分组产生规则如下:

    1、新增记录放到比插入记录主键值大且主键值相隔最近的行记录对应的槽里,并将当前槽对应行记录的n_owned属性+1,表示该槽对应的记录组的记录多了1个。

    2、当记录组的记录数变为9个时,会将这9条记录分为2个组,一组4个一组5个,对于4条记录的分组会将里面相对页起始位置最大的值的行记录的数据部分偏移量(相对页起始位置)设置为新的槽。

    查找记录的规则如下:

    1、通过二分法找到对应的槽。

    2、根据行记录的next_record属性找到对应的行。

    【7】文件尾部

    文件尾部大小为8个字节,前4个字节代表页的校验和,和文件头部的校验和相等就代表是一个完成的页,后4个字android节代表最后一次修改当前页是对应的redo日志序号,这个以后再讲。

    4、总结

    本篇文章讲解了数据页的组成,页是存储数据的基本单位;每个页的文件头部都会有一个上下页号,组成了一个双向链表;页中每条行记录的next_record组成一个单项链表;InnoDB会把多条记录分为一个组,组里的最大记录的数据部分相对于页面开头的偏移量就设置为槽,查找记录时通过二分法查找所在的槽,再通过行记录的next_record属性找到对应的记录。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号