作者:Mayank Prasad
翻译:管长龙
原文:https://mysqlserverteam.com/i...
在 InnoDB 中,用户定义的表及其对应的索引数据存储在扩展名为 .ibd
的文件中。 表空间有两种类型,常规(或共享)表空间和每表独立表空间。 对于共享表空间,来自许多不同表及其对应索引的数据可以驻留在单个 .ibd
文件中。 而对于每表独立表空间,单个表的数据及其索引位于一个 .ibd
文件中。
. IBD 文件
这些文件通常位于数据目录中。 让我们尝试创建一个表 test.t1
。
mysql>CREATE TABLE test.t1 (c INT) engine=InnoDB;
$ cd /test
$ ls
t1.ibd
上面是独立表空间文件,即与表 t1
相关的表和索引数据将驻留在此文件中。
表空间(TABLESPACE)
对于每表独立表空间,表空间名称与 文件/表 名称的名称相同,即对于上面的表 t1
,表空间名称将为 t1
。 如果它是使用名称 my_tablespace
创建的常规(或共享)表空间,则该表空间名称将是 my_tablespace
。
这些表空间用唯一的 ID 标识,称为 tablespace ID。
页(PAGES)
表空间文件由固定大小的页数组成。 有不同类型的页面可用于不同目的。 我们将在接下来的部分中详细介绍所有这些内容。 在此只需记住,表空间文件是许多固定大小的页面的集合。
区(EXTENTS)
区是表空间内连续页面的集合。 区大小为 1 MB。 因此,如果页面大小为 16Kb,则一个区中可能有 64 页。
标头页(HEADER PAGE)
表空间的元数据信息没有单独的存储。 它存储在标头页(始终为 0 页)的同一文件中。现在让我们详细了解一下。
空闲片段列表(FREE FRAGS LIST):
区段链接列表的基节点指针,这些区段具有要“单独”分配的页面。 此列表包含具有至少一个可用页面分配的范围。
完整列表(FULL FRAGS LIST):
区段链接列表的基节点指针,这些区段具有要“单独”分配的页面。 此列表包含没有可用页面分配的范围。
空闲列表(FREE LIST):
区自由分配的链接列表的基本节点指针。 该列表的区可以分配给文件段(稍后描述),也可以分配给空闲片段列表。
XDES 条目(XDES Entries):
表空间中第一组扩展的扩展描述符条目(稍后描述)。
扩展描述符页(XDES页)
区是页的集合。我们需要存储与属于某个范围的页相关的一些元数据信息。 要存储此信息,我们有“扩展描述符页”。
对于 16K 的页大小,一个 XDES 条目(稍后描述)的大小为 40 字节,用于提供有关 64 页的元数据信息。 为了易于实现,一个 XDES 页面条目所覆盖的页面数等于页大小。基于此,可以很容易地找到每个页面大小的 XDES 页中 XDES 条目的数量。
随着表空间的增加(即添加了更多数据),将分配更多的扩展数据块(更多的页)。 一旦区的总数量大于 XDES 页可以跟踪的范围,就会分配一个新的 XDES 页,该页将用于跟踪下一组区。
注意:对于第一组扩展,标头页用于存储 XDES 条目。
下图描述了一个 EXTENT 描述符页和各个 XDES 条目。
注意:列表节点中的上一个和下一个指针指向列表中的 上一个 / 下一个 区:
- FULL,NOT_FULL 和 FREE LIST(如果此区属于文件段)。
- FREE_FRAG,FULL_FRAG,FREE,其它。
一些数字!
一个扩展区大小 = 1 MB
一页大小 = 16 KB
一个区内的总页数 = 64 页
一个 XDES 页中的 XDES 条目总数 = 256
可以在一个 XDES 页面中涵盖总范围 = 256
总页面数可以包含一个 XDES 页面 = 16384
因此,一旦表空间大小超过16384页,我们需要分配一个新的XDES页以保留更多数据区(待分配)。
节点页(INODE PAGE)
这些页面保留有关文件段(FSEG)的信息。 因此,在进入 INDOE 页条目之前,让我们了解文件段。
文件段(FILE SEGMENT)
文件段是一个逻辑单元,是页面和区段的集合。下图描述了文件段的高级逻辑(非物理)视图。
- FRAG ARRAY
分配给该段的单页数组(32个条目)。
- NOT FULL LIST
基本节点指针,指向分配给该段的扩展区的链接列表,并具有至少一个空闲页面。
- FULL LIST
指向分配给此段的扩展区的链表的基本节点指针,并且没有空闲页。
- FREE LIST
指向分配给该段的扩展区的链接列表的基本节点指针,并具有所有可用页。
注意1:FRAG ARRAY 中的页面属于一个区,该区是 FRAG_FULL / FRAG_FREE LIST 的一部分(即文件段 ID 为 0),并在表空间标头页中维护。 如前所述,这些扩展区中的页面被许多段共享。如下图所示:
注意2:当扩展区变为空闲(即不再使用的页面)时,它不会移动到“文件段”的“空闲”列表中。 相反,它将移至在表空间级别维护的 FREE LIST。
问:为什么我们需要文件段?答:这是为了简化页面管理。 因此,一旦删除文件段,就知道要释放所有扩展区和页面。
随着表的增长,它将在每个文件段中分配各个页面,直到片段数组变满为止,然后切换到一次分配一个扩展区,最终切换到一次分配四个扩展区。
INODE 页(重新访问)
现在,让我们回到 INODE 页面。 INODE 页保留文件段的条目,即 INODE 页中的每个条目代表一个文件段。 上面描述的图 6(在其中描述了文件段的高级视图)实际上是 INODE 页面中的条目,被称为“ INODE 文件段条目”。 让我们再来看一看:
问:索引中如何使用文件段?答:InnoDB 中的每个索引(由 B +树表示)使用两个文件段。
- 叶子页段:将叶子页存储在 B 树中。
- 非叶子页段:将非叶子(中间)页面存储在 B 树中。
在页面上,FSEG HEADER 是存储这两个文件段 INODE 条目信息的位置。 从这些条目中,我们查询 INODE 页面以找到相应的文件段信息。
注意:对于索引,因为索引只有一个叶子段和一个非叶子段,所以仅使用根页的 FSEG HEADER 存储这些信息。 对于 B 树中的其余页面,FSEG HEADER 填充为 0。
杰里米·科尔(Jeremy Cole)在他的博客中给出的一个很好的说明性示例:
“例如,在一个新创建的表中,唯一存在的页面将是根页面,它也是一个叶页面,但存在于“内部”文件段中(因此以后不必移动它) 。 “叶”文件段 INODE 列表和片段数组将全部为空。 “内部”文件段 INODE 列表将全部为空,并且单个根页面将在片段数组中。”
摘要
那么,当我们 创建/删除 索引时,它们如何工作?
如上所述,一旦创建索引(即,至少创建根页面),将为该索引分配两个文件段。 一个用于叶子页面,到目前为止将没有页面,一个用于非叶子页面,将仅分配一个页面即根页面。
现在,随着索引大小的增长,即 B 树的增长,
- 新页面在 FRAG ARRAY 中分配。
- 需求跨越 32 页后,便会将一个区分配给分段并将其移至“FREE LIST”。
- 一旦使用了该新扩展区的页面,该扩展区将移至“非完整列表”。
- 一旦使用了该区的所有页面,它将移至“FULL LIST”并分配一个新的区(与步骤 3
- 相同)。
从根页面删除索引后,我们将知道两个文件段。 我们继续将这两个文件段中的所有扩展区标记为空闲。
感谢您使用 MySQL!