0%

MySQL笔记[InnoDB]表-页结构

InnoDB页由以下7个部分组成:
• File Header 文件头
• Page Header 页头
• Infinum和Supermum Records
• User Records 用户记录,即行记录
• Free Space 空闲空间
• Page Directory 页目录
• File Trailer 文件结尾信息

innodb18

一、File Header

用来记录页的一些头信息,共38个字节。

innodb20

innodb21

二、Page Header

页头部分用来记录数据页的状态信息,由14部分组成,占用56个字节。

innodb22

innodb23

三、Infimum和Supermum Records

每个数据页中有两个虚拟行记录,用来限定记录的边界。Infimum记录是比该页中任何主值都小的值,Supermum记录指比任何可能大的值还要大的值;这两个值在页创建时建立,并且不能删除;

innodb24

四、User Record 和 Free Space

User Record即实际存储行记录的内容,InnoDB的表总是B+树索引组织的。

Free Space指空闲空间,是一个链表结构,记录删除后该空间会加入空闲链表中。

五、Page Directory

​ 页目录存放的是记录的相对位置,这里存放的是页的相对位置,不是偏移量。有时这些记录指针称为Slots(槽)或目录槽(Directory Slots)。在InnoDB中并不是每个记录拥有一个槽,而是一个稀疏目录(sparse directory)。

B+树本身并不能找到一条记录,能找到的只是该记录所在的页。数据库把页载入内存,然后通过Page Directory再进行二叉查找,二叉查找的时间 复杂度较低,同时在内存中查找很快,通过会忽略这部分查找所花费的时间,即一个槽中可能包含多条记录。
伪记录infimum的n_owed的值总是1,记录Supermum的n_owed的值的取值范围为[1,8]。其它用户记录的n_owed的取值范围为[4,8]。当记录被插入或删除时需要对槽进行维护操作。
由于Page Directory是一个稀疏目录,二叉查找是个粗略的结果,需要通过Record Header中的next_record来查找相关记录。同时,page directory说明了n_owed的含义,因为这些记录没有包含在page directory中。

六、File Trailer

为了检测页是否正确写了磁盘,因此设置了File Trailer部分。
File Trailer只有一个FIL_PAGE_END_LSN部分,共8个字节。前4个字节代表checksum值,后4个字节和File Trailer中的FIL_PAGE_LSN相同。将这两个值与File Header中的FIL 进行比较,看是否一致;

默认每次从磁盘读取一个页就会检测页的完整性,这有性能开销,通过Innodb_checksums来决定开启或关闭;
5.6.6版本后增加参数innodb_checksum_algorithm来控制checksum函数的算法 ,默认为crc32,可选的值有innodb,crc32,none,strict_innodb,strict_crc32,strict_none。

七、数据页分析示例

执行下面的sql创建好数据:

CREATE TABLE t2(
a INT UNSIGNED NOT NULL AUTO_INCREMENT,
b CHAR(10),
PRIMARY KEY(a)
)ENGINE=INNODB CHARSET=utf8;

DELIMITER$$
CREATE PROCEDURE load_t2(COUNT INT UNSIGNED)
BEGIN
SET @c=0;
WHILE @c < COUNT DO
INSERT INTO t2 SELECT NULL,REPEAT(CHAR(97+RAND()*26),10);
SET @c=@c+1;
END WHILE;
END;
$$

CALL load_t2(100);

SELECT * FROM t2;

使用py_innodb_page_info工具来分析表空间文件t2.ibd:

D:\Python27\python.exe E:/gitrepos/pyscripts/innodb/py_innodb_page_info.py -v D:\wamp\bin\mysql\mysql5.6.17\data\test\t2.ibd
page offset 00000000, page type
page offset 00000001, page type
page offset 00000002, page type
page offset 00000003, page type , page level <0000>
page offset 00000000, page type
page offset 00000000, page type
Total number of page: 6:
Freshly Allocated Page: 2
Insert Buffer Bitmap: 1
File Space Header: 1
B-tree Node: 1
File Segment inode: 1

可以看到page offset 为3时为数据页,用UltraEdit打开t2.ibd文件,数据页从0x000C00(16K*3=0xc00)处开始。

File Header:38个字节

innodb25

• 7A D1 75 2D checksum 4字节
• 00 00 00 03 页的偏移量,从0开始
• FF FF FF FF 前一个页,因为这里只有一页,所以为0xffffffff
• FF FF FF FF 后一个页,因为这里只有一页,所以为0xffffffff
• 00 00 00 00 00 23 53 79 页的LSN
• 45 BF 页的类型,代表数据页
• 00 00 00 00 00 00 暂时不管此值
• 00 00 00 0a 代表space_id

再看看File_Trailer的内容:83 0D C9 E5 00 23 53 79

innodb26

• 83 0D C9 E5 :Checksum值,通过Checksum函数与File_header中的Checksum值比较
• 00 23 53 79:File Header 中的LSN后4位;

接着分析56个字符的Page Header信息,header部分保存了页中行记录的大量细节信息:

PageHeader(56bytes):
PAGE_N_DIR_SLOTS:0x001A
PAGE_HEAP_TOP:0x0DC0
PAGE_N_HEAP:0x8066
PAGE_FREE:0x0000
PAGE_GARBAGE:0x0000
PAGE_LAST_INSERT:0x0DA5
PAGE_DIRECTION:0x0002
PAGE_N_DIRECTION:0x0063
PAGE_N_RECS:0x0064
PAGE_MAX_TRX_ID:0x0000000000000000
PAGE_LEVEL:0x0000
PAGE_INDEX_ID:0x000000001A000000
PAGE_BTR_SEG_LEAF:0x0A000002003201000200
PAGE_BTR_SEG_TOP:0x32010002001C696E6669

PAGE_N_DIR_SLOTS:0x001A表示Page Directory有26个槽,每个槽占2个字节,可以从0x0000ffc4和0x0000fff7.


参考《MySQL技术内幕 -InnoDB存储引擎》整理,如侵权请联系vinin@163.com