[翻译] InnoDB 空间文件布局基础
本系列文章翻译自 Jeremy Cole's Blog 中的 InnoDB系列 文章 。共 16 篇,本文为第 3 篇。原文链接:The basics of InnoDB space file layout
因翻译水品有限,为了避免对读者造成误解,一些专有名词的翻译会在其后用
[]
标记出原文。
InnoDB 空间文件布局基础
在 On learning InnoDB: a journey to the core (译文)一文中,我介绍了用来记录 InnoDB
内部结构的 innodb_diagrams 项目,本文中所使用的图表均可以在该项目中找到。
InnoDB
的数据存储模型称为“空间”,在 MySQL
上下文中通常称为“表空间”,而在 InnoDB
本身中有时也称为“文件空间”。一个空间可能由操作系统层面的多个实际文件(例如 ibdata1
、 ibdata2
等)组成,但它们在逻辑上被当作一个文件,多个物理文件被视为是连接在一起的。
InnoDB
为每个 空间 都分配了一个32位
整数的 空间 ID[space id
],在许多地方都需要使用 空间 ID 来引用 空间。InnoDB
有一个“系统空间”,它的 空间 ID 固定为0
。系统空间 用于记录 InnoDB
需要的各种特殊簿记[bookkeeping
]。在 MySQL
中,除了系统空间,InnoDB
目前只支持file per table
形式的空间,这会为每张表创建一个.ibd
文件。在InnoDB
内部,这个.ibd
文件实际上是一个功能齐全的空间,可以包含多张表,但在 MySQL
的实现中,一个.idb
文件只包含一个表。
页面
每个空间都被划分为许多个页面,通常每个页面的大小为 16KB
(这个页面大小可能因为两方面影响而有所变化:编译时修改了 UNIV_PAGE_SIZE
定义的值,或者使用了 InnoDB
压缩)。InnoDB
为空间中的每个页面都分配了一个32位
的整数页码,通常称为“偏移量”,这实际上只是这个页面 从空间开始位置 的偏移量(因为对于多个文件组成的空间来说,并不一定是 从文件开始位置 的偏移量)。因此,0
号页面 位于偏移量为0
的位置,1
号页面 位于偏移量为16384
的位置,等等。(有的读者可能知道 InnoDB
有一个数据大小限制是64TB
,这实际上是每个空间的大小限制,主要是由于页面号是一个32位
的整数,结合默认的页面大小16KB
可以得到:2<sup>32</sup> x 16 KB = 64 TB)
译者注:这里
InnoDB
的空间大小限制其实还取决于页面的大小,表空间的最大限制 = 2^32 x 页面的大小。官方文档对此也有说明: 14.23 InnoDB Limits
一个页面的基本布局如下:
每个页面都有一个 38字节
的 FIL Header
和 8字节
的 FIL Trailer
(FIL
是“File
”的缩写)。FILE Header
中包含一个字段,表示页面类型,对于页面其余部分,不同类型的页面具有不同的结构。FIL Header
和FIL Trailer
的详细结构如下:
Page Type(2)
:页面类型存储在FIL Header
中。因为页面被用于 文件空间管理、区段管理、事务系统、数据字典、回滚日志[undo log
]、 二进制大对象[blobs
],还有索引(也就是表的数据)等多种用途,不同的用途的页面可能结构不同,所以为了解析页面数据,必须要有页面类型这个字段。Space ID(4)
:当前页面所属空间的空间 ID。Offset(Page Number)(4)
:页码。当页面被初始化后,页码就会存储在FIL Header
中。通过比较 “从该字段读取的页码” 与 “基于文件偏移量的页码” 是否匹配,可以检验页面读取是否正确,并且这个字段被初始化同时就表明页面已经被初始化。Checksum(4)
&Old-style Checksum(4)
:一个32
位的校验和存储在FIL Header
中,一个旧格式[older format
]的(且是破损的)32
位校验和存储在FIL Trailer
中。这个旧格式的校验和在将来可能会被弃用,其空间可能被回收Previous Page(4)
&Next Page(4)
:相同类型页面的逻辑上一页和下一页的指针存储在FIL Header
中。这两个指针是用来构建双向链表的,用于将同一层级的INDEX
类型页面连接起来,这在进行范围扫描的时候是非常有效的,例如全索引扫描。但许多类型的页面其实都不使用这两个字段。LSN for last page modification(8)
&Low 32 bits of LSN(4)
:页面最后一次修改的日志序列号(简写为LSN
,64 位整数)存储在FIL Header
中,并且同一LSN
的低32
位存储在FIL Trailer
中。Flush LSN(8)
:一个64
位的"Flush LSN"
字段存储在FIL Header
中,实际上整个系统中只有0
号空间的0
号页面 使用该字段,这个字段记录了整个系统(所有的空间)中刷新到页面中的最高LSN
。这个字段非常适合在其余空间中用于其他用途。
译者注:
校验和是
InnoDB
用来检验从磁盘中读入内存的一个页面是否损坏的一种机制。写入页面时计算 校验和 写入页面中,当读出页面时再次计算校验和,如果校验和与页面中存储的校验和一致,则说明没有损坏,否则说明页面有损坏。InnoDB 有三种校验算法:
crc32
、innodb
、none
,可以通过 系统变量innodb_checksum_algorithm
来指定,它们之间的区别可以参考官方文档:innodb_checksum_algorithm当校验算法为
crc32
和none
时,FIL Header
和FIL Trailer
中的两个校验和字段的值是相同的,而当校验和为innodb
时,两个校验和字段时不同的。
空间文件
一个空间文件是由许多个页面(最多 2<sup>32</sup> 个)连接而成。为了提高管理效率,这些页面被划分为1 MB
大小的块(页面大小为 16KB
的情况下一块为 64
个连续页面),称为“区段”。许多结构都只按照“区段”为单位在空间内分配页面。
InnoDB
需要使用一些簿记信息来跟踪所有的页面、区段以及空间本身,因此空间文件中有一些必需的“超级结构[super-structure
]”:
空间中的第一个页面(0
号页面)固定为 FSP_HDR
(File Space Header
的简写)页面。FSP_HDR
页面中 包含一个 FSP Header
结构(名字可能容易混淆),用于跟踪空间大小 以及 free
区段链表 、 fragmented
区段链表 和 full
区段链表 等内容。(关于空闲空间管理将在以后的文章中进行更详细的讨论)
一个 FSP_HDR
页面内部的空间仅能够存储 256
个区段(16,384
页,256
MB)的簿记信息,因此需要每隔 16,384
页使用额外的空间来存储 XDES
页面用以记录区段的簿记信息。XDES
页面 和 FSP_HDR
页面的结构是相同的,唯一的区别是 在 XDES
页面中,FSP Header
结构是置为零不使用的。随着空间文件的增长,这些额外的页面会自动分配。
空间中的第三个页面(2
号页面)是一个 INODE
页面,用于存储与文件段相关的列表(文件段可以理解为 区段组成的组 再加上 单独分配的“碎片”页面 组成的数组)。每个 INODE
页可以存储85
个 INODE
条目,每个索引需要两个 INODE
条目。(关于 INODE
条目和 文件段
的内容将在以后的文章进行更详细地讨论)
除了每个 FSP_HDR
页面 和 XDES
页面外,还有 IBUF_BITMAP
页面,用于与插入缓冲[insert buffer
]相关的簿记信息,这不在本文讨论范围之内。
译者注:插入缓冲[
insert buffer
] 又叫做 写缓冲[Change BUffer
],主要用于加速对数据的变更操作,例如INSEERT
、DELETE
、UPDATE
。官方文档:14.5.2 Change Buffer。
系统空间
在 InnoDB
中,系统空间[system space
](空间 ID 为0
)是比较特殊的,它包含了许多分配在固定页码上的页面,用于存储对 InnoDB
的操作至关重要的大量信息。系统空间与其他空间一样,它的前三个页面分配了 FSP_HDR
、IBUF_BITMAP
和 INODE
页面。除此之外,它还有一些其他的特殊页面:
译者注:图中
idbata1
是InnoDB
系统表空间在磁盘上对应的文件名
系统表空间中分配了以下页面:
3
号页面,类型为SYS
:与插入缓冲有关的头部和簿记信息4
号页面,类型为INDEX
:用于插入缓冲的索引树的根页面5
号页面,类型为TRX_SYS
:存储与InnoDB
事务系统的操作有关的信息,例如最新的事务ID
、MySQL
Bin Log
相关的信息以及Double Write Buffer
所在区段的位置6
号页面,类型为SYS
:第一个回滚段的页面。InnoDB
会根据需要分配额外的页面(或整个区段)来存储回滚段数据7
号页面,类型为SYS
:与数据字典相关的头部信息,包含组成数据字典的索引的根页码。通过这些信息能够找到任何其他索引 ,因为它们的根页码存储在数据字典中64
-127
号页面:Double Write Buffer
中的第一块(64
个页面,一个区段)。Double Write Buffer
是InnoDB
崩溃恢复机制的一部分128
-191
号页面:Double Write Buffer
中的第二块
除了这些特殊的页面之外,其他页面都会根据需要分配给索引、回滚段、撤消日志[undo logs
]等。
独立表空间文件
InnoDB
提供了一个file per table
特性,它能够为每个创建的 MySQL
表创建一个文件。正如前文所述,这实际上是为每个表创建一个空间,所以这个特性的一个更好的名称应该是“space per table
”,而不是“file per table
”。为每个表创建的.idb
文件具有典型的空间文件结构:
在必要的3
个初始页面之后,接下来空间中分配的页面是表中每个索引的根页面,按照它们在表创建时定义的顺序排序(这里不考虑表创建之后添加索引的所涉及的fast index creation
特性)。3
号页面是聚簇索引的根页面,4
号页面页是第一个二级索引的根页面,等等。
译者注:
fast index creation
是在MySQL 5.5
中引入的新特性,主要用于加速二级索引的创建和删除,即在创建表之后添加或者删除二级索引时不需要重建整张表。在MySQL 5.6
中,该特性变得更加通用,更多的种类的ALERT TABLE
操作都可以在不复制整张表或者不阻塞DML
操作的情况下执行,所以在MySQL 5.6
中这个特性被称作Online DDL
。相关文档:
由于 InnoDB
的大部分簿记结构都存储在系统空间中,因此在独立表空间中分配的大部分页面都是 INDEX
类型的页面用于存储表数据。
下一步是什么
接下来,我们将研究 InnoDB
中的空闲空间管理: 区段描述符、文件段(inodes
)以及一系列链表结构。
版权声明: 本文为 InfoQ 作者【keaper】的原创文章。
原文链接:【http://xie.infoq.cn/article/0a67a37694993f5e7a36002f9】。文章转载请联系作者。
评论