前言
大家好,我是xicheng。最近天气变凉,留神身材。当初持续更新MySQL的InnoDB的相干文章,InnoDB的常识脑图如下所示,大家坐稳了。
InnoDB页简介
默认是16KB。大小只能在第一次初始化MySQL数据目录时指定。是InnoDB用于存放数据与索引的页。
InnoDB数据页大体构造
名称 | 中文名 | 大小(字节) | 简略形容 |
---|---|---|---|
File Header | 文件头 | 38 | 页的一些通用信息 |
Page Header | 页头 | 56 | 数据页专有的一些信息 |
Infimum + SupreMum | 最小记录和最大记录 | 26 | 两个虚构的行记录 |
User Records | 用户记录 | 不确定 | 理论存储的行记录内容 |
Free Space | 闲暇空间 | 不确定 | 页中尚未应用的空间 |
Page Directory | 页目录 | 不确定 | 页中某些记录的绝对地位 |
File Trailer | 文件尾部 | 8 | 测验页是否残缺 |
如下图所示
File Header
用来记录页的一些头信息。针对各种类型的页都通用File Header属性如下表所示。*为重点把握的属性。
名称 | 占用空间(字节) | 形容 |
---|---|---|
*FIL_PAGE_SPACE_OR_CHKSUM | 4 | ⻚的校验和(checksum值) |
*FIL_PAGE_OFFSET | 4 | ⻚号 |
*FIL_PAGE_PREV | 4 | 上⼀个⻚的⻚号 |
*FIL_PAGE_NEXT | 4 | 下⼀个⻚的⻚号。通过该属性与FIL_PAGE_PREV属性,实现了B+树中,叶子结点是由双向链表形成,能疾速遍历的个性。 |
FIL_PAGE_LSN | 8 | ⻚⾯被最初批改时对应的⽇志序列地位 |
*FIL_PAGE_TYPE | 2 | 该⻚的类型。具体页类型在下表中展现 |
FIL_PAGE_FILE_FLUSH_LSN | 8 | 仅在零碎表空间的⼀个⻚中定义,代表⽂件⾄少被刷新到了对应的LSN值 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4 | ⻚属于哪个表空间 |
页类型,*为重点把握的页类型。
类型名称 | 十六进制 | 形容 |
---|---|---|
FIL_PAGE_TYPE_ALLOCATED | 0x0000 | 最新调配,还没使⽤ |
*FIL_PAGE_UNDO_LOG | 0x0002 | Undo⽇志⻚ |
*FIL_PAGE_INODE | 0x0003 | 段信息节点 |
*FIL_PAGE_IBUF_FREE_LIST | 0x0004 | Insert Buffer 闲暇列表 |
FIL_PAGE_IBUF_BITMAP | 0x0005 | Insert Buffer 位图 |
*FIL_PAGE_TYPE_SYS | 0x0006 | 零碎⻚ |
FIL_PAGE_TYPE_TRX_SYS | 0x0007 | 事务零碎数据 |
FIL_PAGE_TYPE_FSP_HDR | 0x0008 | 表空间头部信息 |
FIL_PAGE_TYPE_XDES | 0x0009 | 扩大形容⻚ |
FIL_PAGE_TYPE_BLOB | 0x000A | BLOB⻚ |
*FIL_PAGE_INDEX | 0x45BF | 索引⻚,也就是咱们所说的数据⻚ |
Page Header
上文列举出了很多种类型的页。其中数据页的属性如下表所示。
状态名称 | 大小(字节) | 形容 |
---|---|---|
PAGE_N_DIR_SLOTS | 2 | 在⻚⽬录中的槽数量,在Page Directory中会讲到 |
PAGE_HEAP_TOP | 2 | 还未使⽤的空间最⼩地址,也就是说从该地址之后就是Free Space |
PAGE_N_HEAP | 2 | 本⻚中的记录的数量(包含最⼩和最⼤记录以及标记为删除的记录) |
PAGE_FREE | 2 | 第⼀个曾经标记为删除的记录地址(各个已删除的记录通过next_record也会组成⼀个单链表,这个单链表中的记录能够被从新利⽤) |
PAGE_GARBAGE | 2 | 已删除记录占⽤的字节数 |
PAGE_LAST_INSERT | 2 | 最初插⼊记录的地位 |
PAGE_DIRECTION | 2 | 记录插⼊的⽅向 |
PAGE_N_DIRECTION | 2 | ⼀个⽅向间断插⼊的记录数量 |
PAGE_N_RECS | 2 | 该⻚中记录的数量(不包含最⼩和最⼤记录以及被标记为删除的记录) |
PAGE_MAX_TRX_ID | 8 | 批改以后⻚的最⼤事务ID,该值仅在⼆级索引中定义 |
PAGE_LEVEL | 2 | 以后⻚在B+树中所处的层级 |
PAGE_INDEX_ID | 8 | 索引ID,示意以后⻚属于哪个索引 |
PAGE_BTR_SEG_LEAF | 10 | B+树叶⼦段的头部信息,仅在B+树的根⻚面定义 |
PAGE_BTR_SEG_TOP | 10 | B+树⾮叶⼦段的头部信息,仅在B+树的根⻚面定义 |
Infimum Record和Supremum Record
每个数据页都有两个虚构的行记录,用来限定记录的边界。Infimum比该页的任何主键值都小。Supremum比该页的任何主键值都大。如下图所示。
User Record和Free Space
User Record是理论存储行记录的内容。
Free Space是闲暇空间,是个链表数据结构。当一条记录被删除后,该空间会被退出到闲暇链表中。
Page Directory
数据页的Page Directory用于在页内疾速查找某条记录。
分组流程
- 初始状况下⼀个数据⻚⾥只有最⼩记录和最⼤记录两条记录,它们分属于两个分组。
- 最⼩记录所在的分组只能有1条记录,最⼤记录所在的分组领有的记录条数只能在1-8条,剩下的分组中记录的条数范畴只能在是4-8条之间。
- 将每个组的最初⼀条记录的地址偏移量依照从小到大的顺序存储到Page Directory里。Page Directory的这些地址偏移量被称为槽。
- 之后每插⼊⼀条记录,都会从⻚⽬录中找到主键值⽐本记录的主键值⼤并且差值最⼩的槽,而后把该槽对应的记录的n_owned值+1,示意本组内⼜增加了⼀条记录,直到该组中的记录数等于8个为止。
- 在⼀个组中的记录数等于8个后再插⼊⼀条记录时,会将组中的记录拆分成两个组,⼀个组中4条记录,另⼀个5条记录。这个过程会更新以后组对应的槽,且另外会新增⼀个槽来记录这个新增分组中最⼤的那条记录的偏移量。
示例
- 初始状况如下图所示,下图中行记录中属性的含意参见“InnoDB与其它存储引擎--InnoDB的行--COMPACT”。该页有2个组。第1组,也就是Infimum Record所在的组只有1条记录。第2组,也就是Supreme Record所在的组有7条记录。
- 插入1条主键值为2的记录:槽1所指的记录的主键值比待插入记录大,且差值最小。将该组的主键最大记录的n_owned +1。也就是将Supreme Record记录的n_owned +1。而后调整next record指针,调整heap no。后果如下图所示。
- 插入1条主键值为3的记录。槽1所指的记录的主键值比待插入记录大,且差值最小。此时,槽1对应的组曾经有8条记录了。则将该组拆分为2组。更新这2组的heap_no,next_record,槽等信息。进一步简化后的示意图如下所示。
⻚中查找指定主键值的记录流程
- 通过⼆分法比拟槽所指记录的主键值与待查键值的大小,来确定待查记录所在的槽。
- 确定槽后,从槽所指的记录开始,通过记录的next_record属性遍历该槽所在的组中的各个记录,至到找到指定主键的记录,或者遍历残缺个组为止。
File Trailer
所有页类型的File Trailer都雷同,一共有8个字节,分成2个局部。
前4个字节代表⻚的校验和(checksum),这个局部和FileHeader中FIL_PAGE_SPACE_OR_CHKSUM绝对应的。具体通过InnoDB的checksum函数来运算两者,将运算后果进行比拟。如果后果雷同,才代表页面被残缺的刷新到了磁盘。(因为刷盘是先刷File Header,后刷File Trailer)
后4个字节与File Header中的FIL_PAGE_LSN雷同,这个局部也是为了校验⻚的完整性的。
结尾
MySQL数据页就讲完了,心愿大家能继续关注上来。下一篇MySQL文章讲InnoDB-表空间。
微信扫描下方二维码,或搜寻“xicheng”,关注公众号后回复【笔记】,有我筹备的15万字Java面试笔记。
感激各位人才的点赞、珍藏和评论,干货文章继续更新中,下篇文章再见!