页(Page)
InnoDB中,页是一次磁盘IO的基本单位,分为数据页和索引页,可以存储多条记录,默认大小为16KB。
例如,假设一条记录大小为8KB,则有:
表空间中现存三个Node类型的页,两个记录叶子节点,一个记录索引节点。
页在表空间的存储形式
如图所示,一个ibd文件中会有多个不同编号(offset)的页。B-tree Node类型的页即是存储B+树节点的单位。
pageLevel则表示当前节点的层数,0000为叶子节点。
页的结构
InnoDB中页分为七个部分,分别为:
-
文件头:页的编号,上下页指针,页的类型(索引、数据)以及页所属表空间
-
Page Header : 当前页中记录数、所在的层级
-
最大、最小记录
-
用户记录 : 按主键升序排列
-
空闲链表:当用户记录被删除时,则加入空闲链表
-
页目录:用来快速查找记录行的位置
- 页目录用来存储每个slot的最后一条记录的地址偏移量,以此二分查找快速定位到记录所在slot(槽、组)
-
文件尾:维护checkSum,检查页的完整性
行格式
InnoDB行格式分为四种:Dynamic,Compressed,redundant以及Compact,不同在于行溢出策略。
Compact一行中,除了存储列之外,额外维护了六个信息,其中包含三个隐藏列。
-
变长字段列表:varchar类型长度不定,这里维护一个长度列表
-
NULL标志位:由于Null值没必要占用存储空间,因此利用位来标志某一列是否为null
-
记录头信息:包含 删除标记,记录类型,下一条记录的指针等、
-
隐藏列:
-
DB_ROW_ID 唯一标识一条记录,优先注解,其次唯一索引,均无则自动生成
-
DB_TRX_ID 记录当前事务id,占用6个字节
-
DB_ROLL_PTR 回滚指针
-
记录在页中的查找方式
在数据页中,用户记录是以链表形式存储,查找过慢。
链表原因:数组增删性能差
InnoDB优化:将所用用户记录分组(Slot),每组最后一个元素地址加入一个有序列表中,通过二分查找列表,快速定位元素所在组。
如何在组内定位记录?
每个组最后一条记录,由n_owned字段定义该组记录个数,以此来计算出该组第一条记录所在位置,遍历即可。
索引页唯一不同点在于,记录中存储的是下一层的页号,即页的偏移量