InnoDB页由以下7个部分组成:
• File Header 文件头
• Page Header 页头
• Infinum和Supermum Records
• User Records 用户记录,即行记录
• Free Space 空闲空间
• Page Directory 页目录
• File Trailer 文件结尾信息
一、File Header
用来记录页的一些头信息,共38个字节。
二、Page Header
页头部分用来记录数据页的状态信息,由14部分组成,占用56个字节。
三、Infimum和Supermum Records
每个数据页中有两个虚拟行记录,用来限定记录的边界。Infimum记录是比该页中任何主值都小的值,Supermum记录指比任何可能大的值还要大的值;这两个值在页创建时建立,并且不能删除;
四、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 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个字节
• 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
• 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。