InnoDB数据页结构
InnoDB数据页由以下7部分组成。
1.File Header(文件头)
2.Page Header(页头)
3,Infimun和supermum Records
4.User Records(用户记录,即行记录)
5.Free Space(空闲空间)
6.Page Directory(页目录)
7.File Trailer(文件结尾信息)
其中File Hdader、Page Header、File Trailer的大小是固定的,分别为38、56、8字节。
这些空间用来标记该页的一些信息,如Checksum,数据页所在B+数据索引的层数等。
User Records、FreeSpace、PageDirectory则写部分实际的行记录存储空间,因此大小是动态的。
1.1FileHeader(文件头)
FileHeader用来记录页的一些信息,如下表:
名称 | 大小(字节) | 说明 |
FIL_PACE_SPACE_OR_CHKSUM | 4 | 当MySQL为MySQL4.0.14之前的版本时,该值为0.之后的MySQL版本中,该值代表页的checksum值(一种新的checksum值) |
FIL_PAGE_OFFSET | 4 | 表空间中页的偏移量。如果独立表空间a.ibd的大小1GB,如果页的大小为16KB,那么总共65535个页。FIL_PAGE_OFFSET表示该页在所有页中的位置。若此表空间的ID为10,那么搜索页(10,1)就表示查找标a中的第二页。 |
FIL_PAGE_PREV | 4 | 当前的上一个页,B+Tree特性决定了叶子节点必须是双向列表 |
FIL_PAGE_NEXT | 4 | 当前的下一个页,B+Tree特性决定了叶子节点必须是双向列表 |
FIL_PAGE_LSN | 8 | 该值代表页最后被修改的日志序列位置lsn(LOG Sequence Number) |
FIL_PAGE_TYPE | 2 | InnoDB存储引擎的类型。记住0x45BF,该值代表了存放的是数据页,即实际行记录的存储空间。 |
FIL_PAGE_FILE_FLUSH_LSN | 8 | 该值仅在系统表空间的一个页中定义,代表文件至少被更新到了该LSN值。对于独立表空间,该值都为0 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4 | 从MySQL4.1开始,该值代表页属于哪个表空间 |
InnoDB存储引擎中页的类型
名称 | 十六进制 | 解释 |
FIL_PAGE_INDEX | 0x45BF | B+树叶节点 |
FIL_PAGE_UNDO_LOG | 0x0002 | UndoLog页 |
FIL_PAGE_INODE | 0x0003 | 索引节点 |
FIL_PAGE_IBUF_FREE_LIST | 0x0004 | InsertBuffer空闲列表 |
FIL_PAGE_TYPE_ALLOCATED | 0x0000 | 该页为最新分配 |
FIL_PAGE_IBUF_BITMAP | 0x0005 | Insert Buffer位图 |
FIL_PAGE_TYPE_SYS | 0x0006 | 系统页 |
FIL_PAGE_TYPE_TRX_SYS | 0x0007 | 事务系统数据 |
FIL_PAGE_TYPE_FSP_HDR | 0x0008 | File Space Header |
FIL_PAGE_TYPE_XDES | 0x0009 | 扩展描述页 |
FIL_PAGE_TYPE_BLOB | 0x000A | BLOB页 |
1.2 Page Header(页头)
File Header 部分之后是Page Header,该部分用来记录数据页的状态信息,由14个部分组成,共占用56字节。
名称 | 大小(字节) | 说明 |
PAGE_N_DIR_SLOTS | 2 | 在PageDirectory(页目录)中的Slot(槽)数。 |
PAGE_HEAP_TOP | 2 | 堆中第一个记录的指针,记录在页中是根据堆的形式存放的 |
PAGE_N_HEAP | 2 | 堆中的记录数,一共占用2字节。但是第15位表示行记录格式 |
PAGE_FREE | 2 | 指向可重用空间的首指针 |
PAGE_GARBAGE | 2 | 已删除记录的字节数,即行记录结构中delete flag为1的记录大小的总数 |
pPAGE_LAST_INSERT | 2 | 最后插入记录的位置。 |
PAGE_DIRECTION | 2 | 最后插入的方向。可能的取值为: PAGE_LEFT(0x01) PAGE_RIGHT(0x02) PAGW_SANE_REC(0x03) PAGE_SAME_PAGE(0x04) PAGE_NO_DIRECTION(0x05) |
PAGE_N_DIRECTION | 2 | 一个方向连续插入记录的数量 |
PAGE_N_RECS | 2 | 该页中记录的数量 |
PAGE_MAX_TRX_ID | 8 | 修改当前页的最大事务ID,注意该值仅在SecondaryIndex中定义 |
PAGE_LEVEL | 2 | 当前页在索引树中的位置,比0小代表页节点,即页节点总是在第0层 |
PAGE_INDEX_ID | 8 | 索引ID,表示当前页属于哪个索引 |
PAGE_BTR_SEG_LEAF | 10 | B+树数据页非叶节点所在段的segment Header。注意该值仅在B+树的Root页中定义 |
PAGE_BTE_SEG_TOP | 10 | B+树数据页所在段的segment Header。注意该值仅在B+树的Root页中定义 |
3.Infimum和Supremum Record
在InnoDB存储引擎中,每个数据页中有两个虚拟的行记录,用来限定记录的边界。Infimum记录是比该页中任何主键值都要小的值,Supremum指比任何可能大的值还要大的值。这两个值在页创建时被建立,并且在任何情况下不会被删除。在Compact行格式和Redundant行格式下,两者所占用的字节数各不相同。
4.User Record和Free Space
User Record是实际存储行记录的内容。InnoDB存储引擎表总是B+数索引组织的。
Free Space很明显指的就是空闲空间,同样也是个链表数据结构。在一条记录被删除后,该空间会被加入到空闲链表中。
5.Page Directory
Page Directory(页目录)中存放了记录的相对位置(这里存放的是页相对位置,而不是偏移量),有些时候这些记录指针成为Slots(槽)或者目录槽(Directory Slots)。与其他数据库系统不同的是,在InnoDB中并不是每个记录拥有一个槽,InnoDB存储引擎的槽是一个系数目录(sparse directory),即一个槽中可能包含多个记录。伪记录Infimum的n_owned值总是为1,记录Supremum的n_owned的取之范围为【1,8】,其他的用户记录n_ownedde取之范围为【4,8】。当记录被插入或删除时需要对槽进行分裂或平衡的维护操作。
在Slots中记录按照索引健值顺序存放,这样可以利用二叉查找迅速找到记录的指针。
假设有(‘i’,‘d’,‘c’,‘b’,‘e’,‘g’,‘l’,'h‘,’f‘,’j‘,’k‘,’a‘),同时假设一个槽中包含4条记录,则Slots中的记录可能是(’a‘,’e‘,’i‘)。
由于在InnoDB存储引擎中PageDirectory是系数目录,二叉树查找的结果指示一个粗略的结果,因此InnoDB存储引擎必须通过recorder header中的next_record来继续查找相关记录。同时,Page Directory很好解释了recorder header中n_owned值的含义,因为这些记录并不包括在Page Directory中。
B+树索引本身并不能找到具体的一条记录,能找到指示该记录所在的页。数据库把页载入到内存,然后通过Page Directory在进行二叉查找。只不过二叉查找的时间复杂度很低,同时在内存中的查找很快,因此通常忽略这部分查找所用的时间。
6 File Trailer
为了检测页是否已经完整地写入磁盘,InnoDB存储引擎的页中设置了File Trailer部分。
File Trailer只有一个FIL_PAGE_END_LSN部分,占用8字节。前4字节代表该页的checksum值,最后4字节和File Header中的FIL_PAGE_LSN相同。将这两个值与File Header 中的FIL_PAGE_SPACE_OR_CHKSUM和FOL_PAGE_LSN值进行比较,看是否一致(比较需要通过InnoDB的checksum函数来进行比较),一次来保证页的完整性。
在默认配置下,InnoDB存储引擎每次从磁盘读取一个页就会检测该页的完整性。这部分的检测会有一定的开销。用户可以通过参数innodb_checksums来开启或关闭这个页完整型的检查。
MySQL5.6.6版本开始增加了参数innodb_checksum_algorithm,该参数用来控制检测checksum函数的算法,默认值为crc32,可设置的值有:innodb、crc32、none、strict_innodb、stric_crc32、strict_none。
i nnodb为兼容之前版本的InnoDB页的checksum检测方式,crc32为MySQL5.6.6版本引进的新的checksum算法,该算法较之前的innodb有着较高的性能。但是若表中所有页的checksum值都已strict算法保存,那么低版本的MySQL数据库将不能读取这些页。none表示不对页启用checksum检查。
strict_*,表示严格按照设置的checksum算法进行页的检测。若较低版本MySQL数据库升级到MySQL5.6.6或之后的版本,启用stric_crc32将导致不能读取表中的页。启用stric_crc32方式是最快的方式,因为其不再对innodb和crc32算法进行两次检测,所以推荐使用该设置。若数据库从低版本升级而来,则需要进行mysql_upgrade操作。
五、Namde File Formates机制
Namde File Formates机制解决不同版本下页结构兼容性问题。
InnoDB存储引擎将1.0.x版本之前的文件格式定义为Antelope,将这个版本支持的文件格式定义Barracuda。新的文件格式总是包含于之前的版本的页格式。
参数innodb_file_format用来指定文件格式,可以通过下面的方式来查看当前所使用的InnoDB存储引擎的格式。
参数innodb_file_format_check用来检测当前InnoDB存储引擎文件格式的支持度,该值默认为ON,如果出现不支持的文件格式,用户可能在错误日志文件中看到类似如下的错误:
InnoDB:Warning:the system tablespace is in a file format that this version donesn't support