MySQL:InnoDB的页合并与页分裂到底是什么

不管是页分裂还是页合并,InnoDB都会在索引树上加写锁(x-latch) 。在操作频繁的系统中这会是在隐患 , 可能会导致索引的锁竞争(index latch contention) 。如果表中没有合并和分裂操作(也就是写操作),称之为“乐观(optimistic)”更新,只需要使用读锁(S) 。带有合并或者分裂的操作称之为“悲观(pessimistic)”更新,使用写锁(X) 。?本文为摘录文章,如有错误,请指正 。文章是以MySQL5.7版本进行说明,和现有版本可能会有一定差距,但是数据页的设计基本没有发生过变化,因此 , 可以作为学习参考 。原文为2017年发表的一篇文章:《InnoDB Page Merging and Page Splitting - Percona Database Performance Blog》 。
1 文件表(File-Table)结构在MySQL5.7创建windmills库(schema)和wmills表,在文件目录(/var/lib/mysql)有如下内容:
data/windmills/wmills.ibdwmills.frm原因是从MySQL5.6开始innodb_file_per_table参数默认设置为1,即:每个表都会单独作为一个文件存储(如果有分区,可能有多个文件) 。如果配置为0,则所有的表都是写入公共表空间 。

  • vmills.ibd文件由多个段(segments)组成,每个段和一个索引有关;
  • 段由多个区构成 , 区仅存于段内 , 每个区的默认固定大小为1MB(页体积默认情况下);
  • 区是由很多数据页构成,默认大小为16KB,即一个分区最多由64个数据页构成 。
  • 数据页可以容纳2-N行数据行 , 行的数量取决于数据行的大?。籌nnoDB要求页至少要有两行,因此行的大小最多为8000bytes 。
  • 文件的结构不会随着数据行的删除而变化,但是段会跟着区的变化而变化;

MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
2 根、分支和叶子(Roots,Branches and Leaves)每个页(逻辑上指的是主键索引的叶子节点)包含2-N行数据行,根据主键排列 , 树有着特殊的页区管理不同的分支,即内部节点(INodes) 。示例如下:
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
ROOT NODE #3: 4 records, 68 bytes NODE POINTER RECORD ≥ (id=2) → #197 INTERNAL NODE #197: 464 records, 7888 bytes NODE POINTER RECORD ≥ (id=2) → #5 LEAF NODE #5: 57 records, 7524 bytes RECORD: (id=2) → (uuid="884e471c-0e82-11e7-8bf6-08002734ed50", millid=139, kwatts_s=1956, date="2017-05-01", locatinotallow="For beauty's pattern to succeeding men.Yet do thy", active=1, time="2017-03-21 22:05:45", strrecordtype="Wit")表结构为:
CREATE TABLE `wmills` (`id` bigint(11) NOT NULL AUTO_INCREMENT,`uuid` char(36) COLLATE utf8_bin NOT NULL,`millid` smallint(6) NOT NULL,`kwatts_s` int(11) NOT NULL,`date` date NOT NULL,`location` varchar(50) COLLATE utf8_bin DEFAULT NULL,`active` tinyint(2) NOT NULL DEFAULT '1',`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`strrecordtype` char(3) COLLATE utf8_bin NOT NULL,PRIMARY KEY (`id`),KEY `IDX_millid` (`millid`)) ENGINE=InnoDB;B+树的根节点就是查询的根节点,如图的#3就是根节点 。根节点(页)包含了索引ID、INodes数量等信息 。INodes页包含了关于页本身的信息、值的范围等 。最后还有叶子节点,存储着具体的数据行的全部数据 。在示例中,叶子节点#5有57行记录,共7524bytes 。这行信息是具体的记录,可以看到数据行内容 。
因此, 使用InnoDB管理表和行,InnoDB会将数据以分支、页和记录形式进行组织 。InnoDB可操的最小粒度是页,页加载进内存后才会通过扫描页获取行数据(即示例中的record) 。
3 页的内部原理(page internals)数据页的数据会按照主键的顺序来排序,这也是我们在设计表主键时设置为AUTO_INCREMENT的原因,这样在频繁插入时,写入的数据尽可能的写入相同的页,写满后刷盘也可以是顺序写 。
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
但是如果页的数据比较?。?就会导致磁盘和内存空间的浪费,因此,如果 页的数据大小/页大小 小于一定比例 , 就会做页合并,这个值我们称之为MERGE_THRESHOLD , 默认值为50% 。
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
当本页数据写满后,就会从内存中申请新页(next)进行写入 。


推荐阅读