不管是页分裂还是页合并,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 。
- 文件的结构不会随着数据行的删除而变化,但是段会跟着区的变化而变化;
文章插图
图片
2 根、分支和叶子(Roots,Branches and Leaves)每个页(逻辑上指的是主键索引的叶子节点)包含2-N行数据行,根据主键排列 , 树有着特殊的页区管理不同的分支,即内部节点(INodes) 。示例如下:
文章插图
图片
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的原因,这样在频繁插入时,写入的数据尽可能的写入相同的页,写满后刷盘也可以是顺序写 。
文章插图
图片
但是如果页的数据比较?。?就会导致磁盘和内存空间的浪费,因此,如果 页的数据大小/页大小 小于一定比例 , 就会做页合并,这个值我们称之为MERGE_THRESHOLD , 默认值为50% 。
文章插图
图片
当本页数据写满后,就会从内存中申请新页(next)进行写入 。
推荐阅读
- 创建一个双模式跨运行时的 JavaScript 包,你学会了吗
- Spring非常实用的技巧,你确定知道?
- Java垃圾回收器的工作原理及监视不再使用对象的机制
- 2024 年 17 个提高生产力的 Chrome 扩展程序
- Java新的结构化并行模式入门指南
- SQL应用于LLM的程序开发利器——开源LMQL
- LangChain与Redis合作搞事情!创建提高财务文档分析准确性的工具
- 连接六大场景,小红书「搜索直达」是2024不容错过的流量机会
- 假扮卧底,骗 AI 泄露代码拯救人类?由 AI 开发的 AI 游戏来了
- 通过网站微调的方式可稳定关键词排名