Innodb 数据页结构

76 阅读3分钟

简介

innodb把存放用户数据的页称作索引(INDEX)页,为了方便,这里称作数据页。innodb数据页一般为16KB,其结构如下:

File Header

File header 对各种类型的页都是通用的,占用固定的38字节。

  1. FIL_PAGE_SPACE_OR_CHKSUM:校验和,4字节;
  2. FIL_PAGE_OFFSET:页号,4字节,每个页都有唯一的页号;
  3. FIL_PAGE_PREV:上一页的页号,4字节;
  4. FIL_PAGE_NEXT:下一页的页号,4字节;
  5. FIL_PAGE_TYPE:页类型,2字节,数据页的类型是FIL_PAGE_INDEX;
  6. FIL_PAGE_LSN:页最后被修改的LSN(log sequence number),8字节;
  7. FIL_PAGE_FILE_FLUSH_LSN:8字节,仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的LSN值
  8. FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID:4字节,页所属的表空间;

Page Header

这里介绍的page header是专门针对数据页的,它占56个字节,这里介绍几个重要的字段:

名称空间(字节)描述
PAGE_N_DIR_SLOTS2Page directory 中slot的数量
PAGE_HEAP_TOP2当前free space的起始地址
PAGE_N_HEAP2本页记录数量,包含最大最小记录,标记删除的记录
PAGE_N_RECS2本页记录数量,不包含最大最小记录和标记删除的记录
PAGE_FREE2第一个标记删除的记录地址,被标记删除的记录通过 next-record 串成一个单链表,这个单链表中的记录可以被重新利用
PAGE_GARBAGE2标记删除的记录占用的字节数
PAGE_LAST_INSERT2最后插入记录的位置
PAGE_MAX_TRX_ID8修改该页的最大事务id,仅在二级索引页中定义
PAGE_LEVEL2该页在B+树中所处的层级
PAGE_INDEX_ID8索引id,代表当前页属于哪个索引

User Records + Page Directory

记录在页中按照主键值由小到大顺序串联成一个单链表,当搜索某个记录时要从头遍历吗?当然不是,这样的时间复杂度是O(n),我们有更快的做法,这就是page directory提出的背景。记录以4-8个为一组,page directory中的每个slot指向对应组中最大的一条记录,这样查找时就能应用二分搜索,将复杂度将为O(logn)。

行格式

上图的记录是一种简化的表示,实际上,每一条记录的行格式由建表时的ROW_FORMAT指定,以Compact为例,它包含下面几部份:

这里重点介绍记录头信息:

名称空间(bit)描述
delete_mask1标记记录是否删除
min_rec_mask1B+树每层非叶子节点中的最小记录都会添加该标记
n_owned4每组最大的记录,用这个字段保存该组记录数量
heap_no13当前记录在本页中的位置,从2开始,0,1是预置的最小最大记录
record_type3表示当前记录的类型,0表示普通记录,1表示B+树非叶节点记录,2表示最小记录,3表示最大记录
next_record16下一条记录指针

File tailer

File tailer由8字节组成,主要用于页完整性的校验:

  1. 前4个字节是校验和,每当一个页面在内存中修改了,在同步之前就要把它的校验和算出来。正常情况下它与File header里的校验和相同,那为什么还要引入它呢?这是因为,假如内存中的数据正在刷盘,刷到一半断电了,为了找到那个刷了一半的页,就需要比对header和tailer中的校验和,如果不一致就代表同步发生了错误。
  2. 后4个字节代表页面被最后修改时对应的日志序列位置(LSN),这个部分也是为了校验页的完整性的。

参考

第5章 盛放记录的大盒子-InnoDB数据页结构