innodb 数据页

innodb 数据页

在前面一系列介绍innodb文章里面多次提到数据页(page)的概念,鉴于数据页是底层ibd最小划分单位,表空间文件就是由一个又一个的页构成,因此页的重要性也就不言而喻,现在我们来具体分析innodb数据页的构成

表空间文件在物理上以16KB为一个步进,Mysql磁盘IO的最小单位,回顾一下整体的表空间文件逻辑结构
file_segment_arch

最底层的ibd物理文件按照16kb的维度划分为一个一个数据页(此处分析不包含page=0,1,2)等元数据信息控制页,想了解这部分内容的可以参考之前介绍的关于段、区的文章段、区描述

照例来看看基础的索引页结构

index_data

  • FIL Header (38) 通常称之为文件头,这个所有的数据页均有此部分
  • Index Header(36) 通常称之为页头
  • Fseg Header(20) 段头,仅在索引页的根节点中设置
  • System Records(26) 系统记录(infimum/supremum)
  • User Records 用户记录
  • Free Spaces 空闲空间
  • Page Directory 页面目录槽
  • FIL Trailer(8) 文件尾部

FIL HEADER/Trailer结构图

file_header_foot

  • Checksum (4) 校验码
  • Offset (Page Number) (4) 页号,亦即PageNo
  • Previous Page (4) 前一页的页号
  • Next Page (4) 后一页的页号
  • LSN for last page modification (8) 最近一次修改page的lsn号
  • Page Type (2) 数据页类型
  • Flush LSN (0 except space 0 page 0) (8) 只用于系统表空间的第一个Page,记录在正常shutdown时安全checkpoint到的点,对于用户表空间,这个字段通常是空闲的
  • Space ID (4) 表空间ID

Fil Trailer

  • Old-style Checksum (4) checksum,用于与header部分的checksum配合工作,检查数据页的完整性
  • Low 32 bits of LSN (4) LSN的低位置4字节

Index Header结构

index_header

  • Number of Directory Slots (2) Page directory中的槽slot个数
  • Heap Top Position (2) 指向当前Page内已使用的空间的末尾位置,即free space的开始位置
  • Number of Heap Records / Format Flag (2) Page内所有记录个数(包含删除的),当第一个bit设置为1时,表示这个page内是以Compact格式存储的
  • First Garbage Record Offset (2) 指向标记删除的记录链表的第一个记录
  • Garbage Space (2) 被删除的记录链表上占用的总的字节数
  • Last Insert Position (2) 指向最近一次插入的记录偏移量,主要用于优化顺序插入操作
  • Page Direction (2) 用于指示当前记录的插入顺序以及是否正在进行顺序插入,插入时,PAGE_LAST_INSERT会和当前记录进行比较,以确认插入方向,据此进行插入优化
  • Number of Inserts in Page Direction (2) 以相同方向的顺序插入记录个数
  • Number of Records (2) Page上有效的未被标记删除的用户记录个数
  • Maximum Transaction ID (8) 最近一次修改该page记录的事务ID
  • Page Level (2) 该Page所在的btree level,根节点的level最大,叶子节点的level为0,非叶子节点以树形结构向上增长
  • Index ID (8) 该Page归属的索引ID

Fseg Header 结构

fseg_header

  • Leaf Pages Inode Space ID (4) 叶子节点的表空间ID
  • Leaf Pages Inode Page Number (4) 叶子节点索引段的页号
  • Leaf Pages Inode Offset (2) 叶子节点索引段entry偏移量(标示具体的inode segment entry 偏移)
  • Internal (non-leaf) Inode Space ID (4) 非叶子节点的表空间ID
  • Internal (non-leaf) Inode Page Number (4) 非叶子节点索引段的页号
  • Internal (non-leaf) Inode Offset (2) 非叶子节点索引段entry偏移量(标示具体的inode segment entry 偏移)

此部分内容值存在于数据页level是根节点(索引根节点)的数据页内

System Records 结构

system_records

  • Info Flags (4 bits) 标记信息
  • Number of Records Owned (4 bits) m_owned值,对于infimum 此值固定为1,下面介绍page slots会解释为什么是1
  • Order (13 bits) 序号,一说为heap_number
  • Record Type (3 bits) 记录类型
  • Next Record Offset (2) 下一个记录的页内偏移位置
  • "infimum\0" (8) 固定"infimum"值
  • Info Flags (4 bits) 标记信息
  • Number of Records Owned (4 bits) m_owned值,对于supremum取值范围为1-8,
  • Order (13 bits) 序号
  • Record Type (3 bits) 记录类型
  • Next Record Offset (2) 下一个记录的页内偏移位置
  • "supremum" (8) 固定"supremum"值

系统记录由innodb自动生成,无需开发人员干预

  • infimum代表当前页比最小记录还小的记录(用作链表的表头)

  • supremum代表当前页比最大记录还大的记录(用作链表的表尾)

此处"最小/最大"记录都是相对于当前页来说的,并不是全局数据节点层面的最大最小记录,主要用于页内数据链表表头/表尾起始结束位置的比对,举个例子,当查询一个id不存在的数据项目时候,load数据页进内存,在内存里面使用2分法查找,找到infimum/supremum记录仍然没有找到指定id记录的时候,此时需要结束查找过程,返回id数据不存在的结果

User Records 用户记录/Free Space

这部分记录即为真实的用户记录存放区域/空闲空间

Page Directory 页面目录槽

前面提到过slots以及owned的概念,之前文章也提到过页面内容的查找是在内存中完成的,内存查找的方法有很多,常见的链表顺序遍历、有序数据结构的二分查找算法、hash查找,目录槽是一个稀疏数组,之前的文章提到过目录槽结构的命令

innodb_space -s /usr/local/var/mysql/ibdata1 -T test/user_info2 -p 6 page-directory-summary 

输出:

slot    offset  type          owned   key
0       99      infimum       1
1       395     conventional  4       (id=89)
2       751     conventional  4       (id=93)
3       1107    conventional  4       (id=97)
4       1463    conventional  4       (id=101)
5       1819    conventional  4       (id=105)
6       2175    conventional  4       (id=109)
7       2531    conventional  4       (id=113)
8       2887    conventional  4       (id=117)
9       3243    conventional  4       (id=121)
10      3599    conventional  4       (id=125)
11      3955    conventional  4       (id=129)
12      4311    conventional  4       (id=133)
13      4667    conventional  4       (id=137)
14      5023    conventional  4       (id=141)
15      5379    conventional  4       (id=145)
16      5735    conventional  4       (id=149)
17      6091    conventional  4       (id=153)
18      6447    conventional  4       (id=157)
19      6803    conventional  4       (id=161)
20      7159    conventional  4       (id=165)
21      7515    conventional  4       (id=169)
22      7871    conventional  4       (id=173)
23      8227    conventional  4       (id=177)
24      8583    conventional  4       (id=181)
25      8939    conventional  4       (id=185)
26      9295    conventional  4       (id=189)
27      9651    conventional  4       (id=193)
28      10007   conventional  4       (id=197)
29      10363   conventional  4       (id=201)
30      10719   conventional  4       (id=205)
31      11075   conventional  4       (id=209)
32      11431   conventional  4       (id=213)
33      11787   conventional  4       (id=217)
34      12143   conventional  4       (id=221)
35      12499   conventional  4       (id=225)
36      12855   conventional  4       (id=229)
37      13211   conventional  4       (id=233)
38      13567   conventional  4       (id=237)
39      13923   conventional  4       (id=241)
40      14279   conventional  4       (id=245)
41      14635   conventional  4       (id=249)
42      112     supremum      7	

这是pageno=6的数据页槽内容

下面这个可以查看pageno=6的数据页内容

innodb_space -s /usr/local/var/mysql/ibdata1 -T test/user_info2 -p 6 page-records 

输出,内容较多,此处只列出了部分内容(含头、尾数据):

Record 128: (id=86) → (name="c6u0olu1t99bintxuwju", phone="00140889180", email="unmg3kktfcfaybsclinz", create_time="184913571-04-58 64:37:75", update_time="1997-02-26 10:06:12")
Record 217: (id=87) → (name="b6zlukjvcijclmtsm61c", phone="73416452518", email="fxtqhwklqfvri0wximdg", create_time="184913571-04-92 19:82:07", update_time="1998-03-21 18:46:44")
Record 306: (id=88) → (name="lwoh05cclf8x5i8mg2g4", phone="23970977406", email="cmopy6gxavhwnbbhsiwh", create_time="184913571-05-25 75:26:39", update_time="1999-04-14 03:27:16")
Record 395: (id=89) → (name="s3hesywuyuiifugxufhk", phone="27097768320", email="ta3nac9mgrjp1s5vbx7x", create_time="184913571-05-59 30:70:71", update_time="2000-05-06 12:07:48")
Record 484: (id=90) → (name="cchc4lnf4dfybc2qpk52", phone="64290362245", email="zyrwthg7pxjnqjuda1r0", create_time="184913571-05-92 86:15:03", update_time="2001-05-29 20:48:20")
Record 573: (id=91) → (name="xvl8gicmu3ls3kperbdk", phone="68101472060", email="b6apbvpuoopi9rasmjio", create_time="184913571-06-26 41:59:35", update_time="2002-06-22 05:28:52")
Record 662: (id=92) → (name="t7kfqinv3nyssli3dipm", phone="17411298527", email="rwrbhq8ghahwn9vrfako", create_time="184913571-06-59 97:03:67", update_time="2003-07-15 14:09:24")
Record 751: (id=93) → (name="huflr7sogkmuye4va97y", phone="25370775440", email="x29tkcz5zrk9crfkplan", create_time="184913571-06-93 52:47:99", update_time="2004-08-06 22:49:56")
Record 840: (id=94) → (name="dnbl0r6ntriomk8vye1i", phone="00944807720", email="qkygjoppuqx1kqxot6jb", create_time="184913571-07-27 07:92:31", update_time="2005-08-30 07:30:28")

....

Record 14546: (id=248) → (name="bgf9zgtnjhjzjncarogy", phone="73579774944", email="xo5pj2mgtfo3wmqzf5xg", create_time="184913571-62-97 11:49:44", update_time="2033-04-22 17:04:20")
Record 14635: (id=249) → (name="yodufhkpu7i57akwb18t", phone="61058341505", email="wljt1vkznox6i7gpdrno", create_time="184913571-63-30 66:93:76", update_time="2034-05-16 01:44:52")
Record 14724: (id=250) → (name="hay9tqm9wx5pcht6weca", phone="83173571461", email="ygjmimuafb3klyb9px1l", create_time="184913571-63-64 22:38:08", update_time="2035-06-08 10:25:24")
Record 14813: (id=251) → (name="tdvgmgsdjiwfzwo7xgjz", phone="69997944082", email="bjf0pxbum1e1yfe1f1co", create_time="184913571-63-97 77:82:40", update_time="2036-06-30 19:05:56")
Record 14902: (id=252) → (name="fhyvivjbvgudqmnbknx7", phone="77376965702", email="4zcwekwqqh5aolmahcn0", create_time="184913571-64-31 33:26:72", update_time="2037-07-24 03:46:28")
Record 14991: (id=253) → (name="tdrqgvp9k231kxgxm62i", phone="11097938259", email="wzf5xgawn1wqmpnao3ud", create_time="184913571-64-64 88:71:04", update_time="2038-08-16 12:27:00")
Record 15080: (id=254) → (name="cdgzudipzxbd8qhnj57a", phone="16963982701", email="zpfa4pg1vp68extfvoh2", create_time="184913571-64-98 44:15:36", update_time="2039-09-08 21:07:32")
Record 15169: (id=255) → (name="bexa9qcpzzlt3pjgyto7", phone="17514550564", email="fjlf6mkr3ogq1omxba5p", create_time="184913571-65-31 99:59:68", update_time="2040-09-16 00:55:28")
  • 可以看到infimum的 owned 值为1,因为infimum前面没有数据记录, infimum为第一条记录,owned只包含它自己

  • id=89 的槽owned值为4,我们看记录可以知道,它前面的数据有id=86,87,88,算上自己89,总共四个值

  • supremum 的owned值7,我们知道上一个槽的key值为249,从记录列表里面可以看到supremum之前有id=250,251,252,253,254,255 共六条记录,算上自己一共七条记录

数据槽/记录的逻辑结构

page_dir

可以看到底层数据行之间顺序关系是链式结构,目录槽记录的是offset(页内偏移),key值为主键ID(对于主索引来说,对于辅助索引的节点key值为对应的辅助索引内容),顺带提一下,数据槽的内容按照offset中对应的key值有序,而非offset排序

综上,owned值将页内数据id按照一定的规则,划分为一个一个的区块,构成一个稀疏的数组,每个owned的区间描述是"(]"前开后闭形式的,描述在此之前有多少个记录,页内数据查找先根据槽信息作2分查找,然后通过链表遍历的方式在区间内做数据最后一层的查找定位

posted @ 2021-06-05 09:33  dev_song  阅读(243)  评论(0编辑  收藏  举报