InnoDB页面结构

InnoDB所有数据文件(ibdata以及ibd)都由页组成。页在内核实现中称为page或block,page偏向于指向物理页面,block偏向于指向page被加载到内存后,用来管理page的内存结构。在未被压缩情况下,一个页的大小为UNIV_PAGE_SIZE(16384,16K)。不同用途的页具有相同格式的文件头和文件尾,其中记录了页面校验值、页面编号、表空间编号、LSN等通用信息。页面的组织方式在《InnoDB物理文件结构》中已有介绍,本文将深入InnoDB页面结构。

1 页面类型

以MySQL-8.0.30为例,所有页面类型如下:

类型 含义
FIL_PAGE_INDEX B+树节点
FIL_PAGE_RTREE R-树节点,R-tree是专门用来表示空间数据类型
FIL_PAGE_SDI SDI是冗余备份的表元数据信息,同样以B+树存储,此为SDI页面类型
FIL_PAGE_TYPE_UNUSED 目前此类型暂未使用
FIL_PAGE_UNDO_LOG 存储undo log的回滚段页面
FIL_PAGE_INODE 用于管理数据文件中的segment,每个inode页可以存储FSP_SEG_INODES_PER_PAGE(默认为85)个记录
FIL_PAGE_IBUF_FREE_LIST change buffer的空闲链表,change buffer介绍详见《Buffer Pool详解
FIL_PAGE_TYPE_ALLOCATED 新分配的页面
FIL_PAGE_IBUF_BITMAP page_no为1、1+16384*N的页面都是FIL_PAGE_IBUF_BITMAP类型,用于记录其后16384个页面change buffer的信息
FIL_PAGE_TYPE_SYS 系统页
FIL_PAGE_TYPE_FSP_HDR page no 0/16384*N的页面都是extent描述页,page no 0还记录了与该table space相关的信息(FSP HEADER),类型为FIL_PAGE_TYPE_FSP_HDR
FIL_PAGE_TYPE_TRX_SYS 事务系统数据
FIL_PAGE_TYPE_XDES 除page no为0的页外所有extent描述页的类型,page no为16384*N
FIL_PAGE_TYPE_BLOB 解压的BLOB页面
FIL_PAGE_TYPE_ZBLOB 第一个压缩的BLOB页面
FIL_PAGE_TYPE_ZBLOB2 后续压缩的 BLOB 页面
FIL_PAGE_TYPE_UNKNOWN 在旧表空间中,FIL_PAGE_TYPE在刷盘时会临时替换为该值
FIL_PAGE_COMPRESSED 压缩页面
FIL_PAGE_ENCRYPTED 加密页面
FIL_PAGE_COMPRESSED_AND_ENCRYPTED 压缩和加密页面
FIL_PAGE_ENCRYPTED_RTREE 加密的 R-tree 页面
FIL_PAGE_SDI_BLOB 未压缩的 SDI BLOB 页面
FIL_PAGE_SDI_ZBLOB 压缩后的 SDI BLOB 页面
FIL_PAGE_TYPE_LEGACY_DBLWR 旧的double write buffer页面
FIL_PAGE_TYPE_RSEG_ARRAY 回滚段数组页面
FIL_PAGE_TYPE_LOB_INDEX 未压缩 LOB 的索引页
FIL_PAGE_TYPE_LOB_DATA 未压缩 LOB 的数据页
FIL_PAGE_TYPE_LOB_FIRST 未压缩 LOB 的第一页
FIL_PAGE_TYPE_ZLOB_FIRST 压缩 LOB 的第一页
FIL_PAGE_TYPE_ZLOB_DATA 压缩 LOB 的数据页
FIL_PAGE_TYPE_ZLOB_INDEX 压缩 LOB 的索引页。 此页面包含一个 z_index_entry_t 对象数组。
FIL_PAGE_TYPE_ZLOB_FRAG 压缩 LOB 的片段页面
FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY 片段页的索引页(压缩的 LOB)

2 通用页面结构

任何页面都有统一的文件头和文件尾结构,用于记录页面的checksum校验、页面类型,用于维护逻辑页面链表的前后逻辑页面编号等。详细结构如下:

image.png

2.1 Fil Header

名称 大小 内容
FIL_PAGE_SPACE_OR_CHKSUM 4 MySQL4.0之前为space id,之后为CHECKSUM
FIL_PAGE_OFFSET 4 页码,每个表空间从0开始计数。页码乘以页面大小便是当前页面在数据文件中的偏移
FIL_PAGE_PREV 4 指向B+树同一层的前一个页面,第一个页面的FIL_PAGE_PREV为FIL_NULL
FIL_PAGE_NEXT 4 指向B+树同一层的下一个页面,最后一个页面的FIL_PAGE_NEXT为FIL_NULL
FIL_PAGE_LSN 8 LSN是一个一直递增的整型数字,表示事务写入到日志的字节总量,可以唯一区分对数据页的修改,此处记录页面最后一次修改的LSN
FIL_PAGE_TYPE 2 页面的类型
FIL_PAGE_FILE_FLUSH_LSN 8 两种作用:1)在系统表空间的第一个页中,记录MySQL关闭时checkpoint到的点,即刷入磁盘的页面LSN至少在该值之上;2)只在FIL_PAGE_COMPRESSED类型的数据页中被用于记录压缩信息
FIL_PAGE_SPACE_ID 4 索引页所在的表空间的ID

2.2 Fil Trailer

文件尾的作用是校验文件是否损坏,在每个页面的结尾的8个字节中,分别存储了checksum和LSN的后四位,对应于Fil Header中FIL_PAGE_LSN的内容。

3 索引页结构

InnoDB的用户表数据存储于FIL_PAGE_INDEX(通常称为索引页)类型的页面中,是InnoDB最重要的页面类型之一。下面介绍其页面结构:

image.png

3.1 Record

为了更好地理解Page Header和Page Directory。先介绍InnoDB索引页中记录的排列方式。记录的格式可以按如下格式理解。

变长字段长度 NULL 标志位 记录头信息 系统列 Field 1 ... Field N

其中记录头信息中包含了next_record、heap_no、delete_flag、n_owned等重要信息。下面依次介绍:

  • next_record:所有记录在页面中从前往后插入。假设id为primary key,id为1,3,2的三条记录依次插入同一页面,那么在页面中三条记录的排列顺序也为1,3,2。三条记录通过next_record属性相连,即id为1的记录的next_record指向id为2的记录,id为2的记录next_record指向id为3的记录。
  • heap_no:记录在页面中的物理编号,上述id为1,3,2的三条记录的heap_no依次为N,N+1,N+2。
  • delete_flag:记录被删除后并不是直接在页面中抹去,而是标记上delete_flag。这样做的目的是为了多版本并发控制服务(MVCC)。页面中被delete mark的记录也会通过next_record串联成链表,记录在Page Header中。当记录不再被MVCC需要时,会由purge线程从页面中彻底抹去。
  • n_owned:本属性与Page Directory相关,在Page Directory小节中介绍。

每个索引页为了方便对页内记录的访问,都添加了两条系统记录,它们没有变长字段列表和NULL值列表,只包含记录头信息和真实数据:infimum和supremum,分别代表虚拟的最小记录和虚拟最大记录。这两条记录固定在Page Header之后,分别是heap_no为0和heap_no为1的记录。从虚拟记录infimum开始一直通过next_record指针访问到虚拟记录supremum,可以按逻辑大小遍历页内的所有记录。

3.2 Page Directory

InnoDB B+树记录查询只能查询到数据页级别。假设一条记录的大小50字节,一个16384字节的页面可以存储300条记录左右,如果页内查询如果都通过next_record从infimum遍历到supremum,那么查询将非常低效。

Page Directory如其名,作为数据目录,是用来加速页内记录查找的。其由一个个slot组成,每个slot由两个字节组成,每个Slot指向一条记录,Slot的值是记录在页面内的偏移。每个Slot管理4~8条记录。被指向的记录作为组长记录,管理位于其之前的4-8条记录。组长记录的n_owned为其管理的记录数量。

image.png

如图所示,Rec5管理Rec1-Rec5,n_owned为5;Rec10管理Rec6-Rec10,n_owned为5;Rec11管理Rec11-Rec14,n_owned为4;Rec18管理Rec15-Rec18,n_owned为4。

一个page至少有两个Slot,第一个slot指向infimum记录,最后一个Slot指向supremum记录。Slot分配是从页面的最后倒数8个字节的Fil Trailer开始逆序分配的,所以严格意义上上图的Slot1-Slot4应该逆序。

在查找时首先数据目录上对Slot进行二分查找,定位到具体的slot后,然后在Slot内进行顺序查找。

3.3 Free Space

这部分是介于用户记录和Page Directory之间的一块连续的未被使用的内存。用户记录从前往后增长,Page Directory从后往前增长。在空间足够时,会直接从这里分配内存,当空间不足时,会重新整理页面内的记录,将碎片空间进行合并,或者分裂页面,具体行为取决于InnoDB各场景下的具体策略。在将空间分配给记录后,会递增PAGE_N_RECS和PAGE_N_HEAP的值。

3.4 Page Header

有了前三小节的介绍,下面对Page Header进行介绍。Page Header主要索引页内的统计信息,包含14部分,如下所示:

名称 大小 含义
PAGE_N_DIR_SLOTS 2 Page directory中的Slot个数
PAGE_HEAP_TOP 2 空余空间的起始地址在页内的偏移,如有新数据将从此位置插入
PAGE_N_HEAP 2 页面内所有的记录数:系统记录(Infimum和Supremum记录)、用户记录、标记被删除的记录。标记删除记录并不会减少此值。
PAGE_FREE 2 指向被标记删除的记录链表的第一个记录。通过此记录可以访问所有标记删除的记录
PAGE_GARBAGE 2 被标记删除的所有记录占用的总字节数,即可回收的空间大小
PAGE_LAST_INSERT 2 指向最近一次被插入记录的偏移量
PAGE_DIRECTION 2 最近一次记录插入的方向(从左或从右插入),每次插入时与PAGE_LAST_INSERT的记录进行比较,以确认插入方向
PAGE_N_DIRECTION 2 当前以相同方向顺序插入记录的个数
PAGE_N_RECS 2 页面上有效的用户记录的个数(不包括最小和最大记录以及被标记为删除的记录)
PAGE_MAX_TRX_ID 8 修改当前页面的最大事务ID,主要用于辅助判断二级索引记录的可见性。
PAGE_LEVEL 2 当前页面在B+树中所在的层数,叶子结点的值为0
PAGE_INDEX_ID 8 索引ID,表示当前页属于哪个索引
PAGE_BTR_SEG_LEAF 10 仅仅在B+树root页定义,叶子节点段在inode page中的位置
PAGE_BTR_SEG_TOP 10 仅仅在B+树root页定义,非叶子节点段在inode page中的位置

4 总结

本文在《InnoDB物理文件结构》的基础上进一步介绍了InnoDB的页面结构。首先介绍了所有InnoDB的页面类型,接着介绍了InnoDB页面的通用页面结构Fil Header和Fil Trailer,最后从Record、Page Directory、Free Space和Page Header四个方面介绍了InnoDB索引页的结构。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 一、页 1、数据库的存储结构——页 索引结构给我们提供了高效的索引方式,不过索引信息以及数据记录都是保存在文件上的...
    紫荆秋雪_文阅读 251评论 0 0
  • 不同类型的页简介 前边我们简单提了一下页的概念,它是InnoDB管理存储空间的基本单位,一个页的大小一般是16KB...
    tracy_668阅读 1,149评论 1 6
  • 简介 从InnoDB逻辑存储结构来看,InnoDB所有数据都存放到在一个空间中,称之为表空间。如图所示,表空间由段...
    呼呼菜菜阅读 470评论 0 2
  • 自己分析一下ibd文件还是蛮有意思的,能够学到不少东西,建议跟着走一遍,慢慢领会作者设计的意图人学东西总是先感性的...
    漫步无法人生阅读 3,861评论 2 11
  • 1. 索引组织表 ​ 在InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式的表称为索引...
    Benjamin_Lee阅读 139评论 0 0