写文章
InnoDB中的页合并与分裂
Python Web后端 / 努力成为Redis砖家
15 人赞同了该文章
如果你找过任何一位MySQL顾问,问他对你的语句和/或数据库设计的建议,我保证他会跟你讲主键设计的重要性。特别是在使用InnoDB引擎的情景,他们肯定会给你解释索引合并和页分裂这些。这两个方面与性能息息相关,你应该在任何设计索引(不止是主键索引)的时候都将他们考虑在内。
你可能觉得这些听起来挺莫名其妙,没准你也没错。这不是容易的事,特别是讲到关于内部实现的时候。通常你都不会需要处理这些事情,并且你也不想去着手他们。
但是有时候这些问题又是必须搞清楚的。如果有这种情况,那这篇文章正适合你。
我尝试用这篇文章将一些最不清晰、InnoDB内部的操作解释清楚:索引页的创建、页合并和页分裂。
在InnoDB中,数据即索引(译注:索引组织数据)。你可能听过这种说法,但它具体是什么样的?
文件表(File-Table)结构
假设你已经装好了MySQL最新的5.7版本(译注:文章发布于17年4月),并且你创建了一个windmills库(schema)和wmills表。在文件目录(通常是/var/lib/mysql/)你会看到以下内容:
data/
windmills/
wmills.ibd
wmills.frm
这是因为从MySQL 5.6版本开始innodb_file_per_table参数默认设置为1。该配置下你的每一个表都会单独作为一个文件存储(如果有分区也可能有多个文件)。
目录下要注意的是这个叫wmills.ibd的文件。这个文件由多个段(segments)组成,每个段和一个索引相关。
文件的结构是不会随着数据行的删除而变化的,但段则会跟着构成它的更小一级单位——区的变化而变化。区仅存在于段内,并且每个区都是固定的1MB大小(页体积默认的情况下)。页则是区的下一级构成单位,默认体积为16KB。
按这样算,一个区可以容纳最多64个页,一个页可以容纳2-N个行。行的数量取决于它的大小,由你的表结构定义。InnoDB要求页至少要有两个行,因此可以算出行的大小最多为8000 bytes。
听起来就像俄罗斯娃娃(Matryoshka dolls)一样是么,没错!下面这张图能帮助你理解:
根,分支与叶子
每个页(逻辑上讲即叶子节点)是包含了2-N行数据,根据主键排列。树有着特殊的页区