innodb行记录、数据组织形式
  1. 2023-05-13
    1. 1. innodb页
      1. 页是什么?为什么要有页的概念?
    2. 2. innodb页的结构
      1. 在讲页的结构之前,需要先了解innodb中数据的“行格式”
      2. innodb的页结构

2023-05-13

1. innodb页

页是什么?为什么要有页的概念?

概念:页是innodb中磁盘和内存交互的基本单位,默认大小是16K。
意义:innodb是把数据存储在硬盘上的,但是在处理数据的时候却是在内存中的,如果在处理数据的时候把数据一条条数据的加载到内存或者写入到磁盘,那么就会导致innodb的读写效率十分的低,所以有了页的概念,可以使innodb一次性读出或写入多条数据

2. innodb页的结构

在讲页的结构之前,需要先了解innodb中数据的“行格式”

数据是以记录的形式存储在磁盘中的,那么数据是如何组织起来进行存放的呢?“行格式”就是规定了数据如何存放的一个协议,所以“行格式”也称为“记录格式”

  • 行格式的种类:
    • compact

      从图来看,行格式分为两部分,一部分用于记录额外信息,一部分用于记录真实数据。
    • redundant
    • dynamic
    • compressd
  • compact:
    变长字段的记录:部分字段的长度不固定,为了可以让innodb更好地处理此类字段,所以记录了该类字段的一些信息。
    这些信息的记录规则是:将每一列变长字段的长度按照逆序存放。
    NULL值记录:当某个字段的值是NULL时,如果我们还将该字段记录在真实数据记录中,这样无疑会浪费空间,所以在compact中,将NULL值进行记录
    记录头信息:记录头信息大小为5byte,共40个二进制位,共记录了_删除标记_、B+树中每层非叶子结点最小记录标识_、_当前记录拥有的记录数_、_当前记录在记录堆中的信息_、_记录类型_、_下一条记录的相对位置
    记录的真实数据:除了我们存储的字段外,innodb会给每条记录添加三列隐藏列——“row_id”、“transaction_id”、“roll_pointer”,分别代表“行记录ID”、“事务ID”、“回滚ID”。其中“row_id”是当用户没用定义主键且没有唯一键时用来充当“主键”的。
  • redundant:
    字段长度偏移列表:相比于compact格式,redundant格式在额外信息中记录的并不是变长字段列表,而是字段长度偏移量。也正是因为redundant没有记录变长字段的列表,所以它是将所有列的长度信息都按逆序的方式存储下来了。
    记录头信息:相比于compact格式,redundant格式的记录头信息的长度是6字节,48个二进制位,记录了_删除标记_、_B+树中每层非叶子结点最小记录标识_、_当前记录拥有的记录数_、_当前记录在记录堆中的信息_、_该记录中列的数量_、_标记长度偏移列表中每个列对应的偏移量是用1字节还是2字节表示的_、_下一条记录的绝对位置_。
    与compatct格式不同的是,多了“记录中列数量”、“偏移量的长度标识”,compact用相对位置标识下一条记录,而redundant用绝对位置标识。
    与compact的不同之处
    • 多了“记录中列数量”、“偏移量的长度标识”
    • compact用相对位置标识下一条记录,而redundant用绝对位置标识。
    • redundant没有“记录类型”
    • redundant中使用字段偏移量中的第一个比特位标识该列是否是NULL,而compact是用NULL列表来记录
  • 行溢出:
    数据页的基本大小为16k,但是有可能一条记录的大小就超过了16k,此类情况成为行溢出。
  • dynamic和compressd:
    这两种行格式与compact很像,区别是处理行溢出的方式不同,dynamic是将所有的字节存储到另外一个页里,compressd是在dynamic的基础上应用了压缩算法。
  • 行记录中的字段含义:
    • deleta_mask(删除标识):当我们删除某一条记录的时候,innodb只是将该记录对应的delete_mask置为了1,而不是立马从磁盘上删除掉这条数据,原因是因为删除数据后需要重新排列,十分消耗性能。这些被删除的记录会组成一个垃圾链表,当有新数据要插入时,可以覆盖这些记录。
    • heap_no(当前记录在该页中的位置):位置都是从2开始的,因为0、1被两条虚拟记录占了,这两条虚拟记录分别是最大记录(supremum)和最小记录(infinum)
    • record_type(记录标识):共四种记录类型,0-普通记录,1-B+树非叶子结点记录,2-最小记录,3-最大记录。

innodb的页结构

  • file header:文件头,占38byte,存储页的通用信息
  • page header:页头,占56byte,存储页的专有信息
  • infinum + supremum:占26byte,本页中数据的最小记录和最大记录
  • user records:大小不定,用户存储的记录
  • free space:大小不定,空余空间
  • page directory:大小不定,页面中某些记录的相对位置
  • file trailer:占8byte,校验页的完整性

page directpry页目录
页目录类似书本的目录,用于帮innodb快速定位目标数据,它的形成如下:

  1. 将数据记录进行分组
  2. 每组的最后一条记录的记录头信息中的n_owner字段记录了改组中拥有几条记录
  3. 将每组的最后一条记录的偏移量提取出来放在页尾,也就是page directory中。

page header页的头部
页头用于存储本页专有的一些信息,如下:

  • PAGE_N_DIR_SLOTS:页中的槽数量
  • PAGE_HEAP_TOP:还未使用的空间最小地址,也就是说从该地址之后就是Free Space
  • PAGE_N_HEAP:本页中的记录的数量(包括最小和最大记录以及标记为删除的记录)
  • PAGE_FREE:第一个已经标记为删除的记录地址(各个已删除的记录通过next_record也会组成一个单链表,这个单链表中的记录可以被重新利用)
  • PAGE_GARBAGE:已删除记录占用的字节数
  • PAGE_LAST_INSERT:最后插入记录的位置
  • PAGE_DIRECTION:记录插入的方向
  • PAGE_N_DIRECTION:一个方向连续插入的记录数量
  • PAGE_N_RECS: 该页中记录的数量(不包括最小和最大记录以及被标记为删除的记录)
  • PAGE_MAX_TRX_ID:修改当前页的最大事务ID,该值仅在二级索引中定义
  • PAGE_LEVEL:当前页在B+树中所处的层级
  • PAGE_INDEX_ID:索引ID,表示当前页属于哪个索引
  • PAGE_BTR_SEG_LEAF:B+树叶子段的头部信息,仅在B+树的Root页定义
  • PAGE_BTR_SEG_TOP:B+树非叶子段的头部信息,仅在B+树的Root页定义

File Header文件头部
所有的页通用的结构,存储信息如下:

  • FIL_PAGE_SPACE_OR_CHKSUM:页的校验和(checksum值),把一个较长的字符串转换为较短的字符串,在比较这个字符串之前可以先比较校验和,如果校验和都不一样的话,那么参与比较的俩字符串肯定不一样
  • FIL_PAGE_OFFSET:页号
  • FIL_PAGE_PREV:上一个页的页号
  • FIL_PAGE_NEXT:下一个页的页号
  • FIL_PAGE_LSN:页面被最后修改时对应的日志序列位置
  • FIL_PAGE_TYPE:该页的类型
  • FIL_PAGE_FILE_FLUSH_LSN:仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的LSN值
  • FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID:页属于哪个表空间