MySQL基础 - InnoDB表空间

表空间都是由页组成的

  • 1.通过页的类型知道该页的作用
  • 2.不同类型的页只有File Header和File Trailer是必须存在的
  • 3.每个表空间中一个页有一个页号,是4个字节,也就是32比特,所以最多有2³²个页
  • 4.如果每个页默认大小16KB则一个表空间最多支持64TB,页号从0开始。
  • 5.而是根据FIL_PAGE_PREV和FIL_PAGE_NEXT来存储上一个页和下一个页的页号。需要注意的是,这两个字段主要是为了INDEX(索引页)类型的页--也就是说其他页是不使用链表来进行连接。

独立表空间结构

  • 1.因为表空间里面页太多了,所以提出区的概念
  • 2.对于16KB的页来说,连续64个页就是一个区,也就是说一个区默认是1MB空间大小。
  • 3.不论是系统表空间还是独立表空间,都可以看出若干个区组成的。
  • 4.每256个区被划分为成一组
  • 5.每个组的最开始的几个页面类型是固定的
  • 6.设置区的原因是因为:为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区为单位分配,甚至在表中的数据十分非常特别多的时候,可以一次性分配多个连续的区
    这样的好处就是我们如果返回查询时候,在物理空间上页很近这就是顺序IO,如果只按照页分配,那么页有可能
    是物理上很远这就会发生随机IO。

  • 1.上述第六点说的很明白了,为啥使用区。
  • 2.如果不区分叶子节点和非叶子节点使用的区的话,就有可能会有部分叶子节点在A区,部分叶子节点在B区
  • 3.这样就会导致我们范围查询效果不太好,因此叶子节点有自己独有的区,非叶子节点也有自己独有的区。
  • 4.各个区的集合就是段,就是说一个索引会生成2个段,一个叶子节点段,一个非叶子节点段。
  • 5.这个段和组不一样,组只是区的集合不区分是否为叶子节点,而段是区分是否为叶子节点的区集合。
  • 6.段是以区为单位申请存储空间的,一个区默认占用1M存储空间,为了避免每个索引都需要申请一个2M内存,提出了一个碎片(fragment)区。
  • 7.碎片区中的页可以用于不同的目的,比如有些页用于段A,有些页用于段B,有些页甚至哪个段都不属于
  • 8.碎片区直属于表空间,并不属于任何一个段。

段分配存储空间的策略

  • 1.在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的
  • 2.当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间。

区的分类

  • 1.空闲的区:现在还没有用到这个区中的任何页面。--FREE
  • 2.有剩余空间的碎片区:表示碎片区中还有可用的页面。--FREE_FRAG
  • 3.没有剩余空间的碎片区:表示碎片区中的所有页面都被使用,没有空闲页面。--FULL_FRAG
  • 4.附属于某个段的区。每一个索引都可以分为叶子节点段和非叶子节点段,除此之外InnoDB还会另外定义一些特殊作用的段,在这些段中的数据量很大时将使用区来作为基本的分配单位--FSEG
  • 5.处于FREE、FREE_FRAG以及FULL_FRAG这三种状态的区都是独立的,而处于FSEG状态的区是附属于某个段的

XDES Entry

  • 1.每一个区都对应着一个XDES Entry结构,结构记录了对应的区的一些属性,具体如下:
  • 2.Segment ID--每一个段都有一个唯一的编号,用ID表示。前提是该区已经被分配给某个段了,不然的话该字段的值没啥意义
  • 3.List Node--这个部分可以将若干个XDES Entry结构串联成一个链表,大家看一下这个List Node的结构:Pre Node Page Number和Pre Node Offset的组合就是指向前一个XDES Entry的指针和Next Node Page Number和Next Node Offset的组合就是指向后一个XDES Entry的指针。
  • 4.State-也就是FREE、FREE_FRAG、FULL_FRAG和FSEG
  • 5.Page State Bitmap--这个部分共占用16个字节,也就是128个比特位。我们说一个区默认有64个页,这128个比特位被划分为64个部分,每个部分2个比特位,对应区中的一个页
    比如Page State Bitmap部分的第1和第2个比特位对应着区中的第1个页面,第3和第4个比特位对应着区中的第2个页面,
    这两个比特位的第一个位表示对应的页是否是空闲的,第二个比特位还没有用.

XDES Entry链表

某个段中插入数据的过程:

  • 1.当段中数据较少的时候,首先会查看表空间中是否有状态为FREE_FRAG的区
  • 2.如果找到了,那么从该区中取一些零碎的页把数据插进去;否则到表空间下申请一个状态为FREE的区,也就是空闲的区,把该区的状态变为FREE_FRAG.
    然后从该新申请的区中取一些零碎的页把数据插进去.
  • 3.之后不同的段使用零碎页的时候都会从该区中取,直到该区中没有空闲空间,然后该区的状态就变成了FULL_FRAG。
  • 4.当段中数据已经占满了32个零散的页后,就直接申请完整的区来插入数据了。

如何快速知道表空间的区处于什么状态。(表空间维护三个链表)

  • 1.把状态为FREE的区对应的XDES Entry结构通过List Node来连接成一个链表,这个链表我们就称之为FREE链表
  • 2.把状态为FREE_FRAG的区对应的XDES Entry结构通过List Node来连接成一个链表,这个链表我们就称之为FREE_FRAG链表。
  • 3.把状态为FULL_FRAG的区对应的XDES Entry结构通过List Node来连接成一个链表,这个链表我们就称之为FULL_FRAG链表。

我们怎么知道哪些区属于哪个段的呢

  • 1.为每个段中的区对应的XDES Entry结构建立了三个链表:
  • 2.FREE链表:同一个段中,所有页面都是空闲的区对应的XDES Entry结构会被加入到这个链表。注意和直属于表空间的FREE链表区别开了,此处的FREE链表是附属于某个段的。
  • 3.NOT_FULL链表:同一个段中,仍有空闲空间的区对应的XDES Entry结构会被加入到这个链表
  • 4.FULL链表:同一个段中,已经没有空闲空间的区对应的XDES Entry结构会被加入到这个链表。
  • 5.每一个索引都对应两个段,每个段都会维护上述的3个链表。

链表基节点--找到某个链表的头节点或者尾节点在表空间中的位置

  • 1.设计了一个叫List Base Node的结构--每个链表都对应这么一个List Base Node
  • 2.结构如下:List Length-表明该链表一共有多少节点
  • 3.First Node Page Number和First Node Offset表明该链表的头节点在表空间中的位置
  • 4.Last Node Page Number和Last Node Offset表明该链表的尾节点在表空间中的位置
  • 5.一般我们把某个链表对应的List Base Node结构放置在表空间中固定的位置,这样想找定位某个链表就变得so easy啦。

链表小结

  • 表空间是由若干个区组成的,每个区都对应一个XDES Entry的结构,直属于表空间的区对应的XDES Entry结构可以分成FREE、FREE_FRAG和FULL_FRAG这3个链表;
    每个段可以附属若干个区,每个段中的区对应的XDES Entry结构可以分成FREE、NOT_FULL和FULL这3个链表。
    每个链表都对应一个List Base Node的结构,这个结构里记录了链表的头、尾节点的位置以及该链表中包含的节点数。
    正是因为这些链表的存在,管理这些区才变成了一件so easy的事情。

段的结构

  • 1.段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念
  • 2.定义了一个INODE Entry结构来记录一下段中的属性
  • 3.Segment ID:就是指这个INODE Entry结构对应的段的编号(ID)
  • 4.NOT_FULL_N_USED:这个字段指的是在NOT_FULL链表中已经使用了多少个页面。下次从NOT_FULL链表分配空闲页面时可以直接根据这个字段的值定位到。而不用从链表中的第一个页面开始遍历着寻找空闲页面。
  • 5.3个List Base Node:分别为段的FREE链表、NOT_FULL链表、FULL链表定义了List Base Node
  • 6.Magic Number:这个值是用来标记这个INODE Entry是否已经被初始化了(初始化的意思就是把各个字段的值都填进去了)
  • 7.Fragment Array Entry:4个字节,对应着零散的页面集合。

各类型页面详细情况

FSP_HDR类型

  • 1.它存储了表空间的一些整体属性以及第一个组内256个区的对应的XDES Entry结构
  • 2.第一个组的第一个页面,当然也是表空间的第一个页面,页号为0

FSP_HDR的五个部分

  • 1.File Header:页的一些通用信息
  • 2.File Space Header:表空间的一些整体属性信息
  • 3.XDES Entry:存储本组256个区对应的属性信息
  • 4.Empty Space:用于页结构的填充,没啥实际意义
  • 5.File Trailer:校验页是否完整

File Space Header

  • 1.存储直属表空间的基节点
  • 2.FREE_FRAG链表中已经使用的页面数量,方便之后在链表中查找空闲的页面。
  • 3.FREE Limit--在该字段表示的页号之前的区都被初始化了,之后的区尚未被初始化。
  • 4.Next Unused Segment ID:通过这个为新创建的段设置ID。
  • 5.Space Flags:表空间的一些布尔值属性。
  • 6.每个段对应的INODE Entry结构会集中存放到一个类型位INODE的页中
  • 7.INODE类型的页会组成两种列表:
  • 8.SEG_INODES_FULL链表:该链表中的INODE类型的页面都已经被INODE Entry结构填充满了,没空闲空间存放额外的INODE Entry了
  • 9.SEG_INODES_FREE链表:该链表中的INODE类型的页面都已经仍有空闲空间来存放INODE Entry结构。

XDES Entry部分

  • 1.XDES Entry就是在表空间的第一个页面中保存的
  • 2.我们知道一个XDES Entry结构的大小是40字节,但是一个页面的大小有限,只能存放有限个XDES Entry结构,所以我们才把256个区划分成一组,在每组的第一个页面中存放256个XDES Entry结构

XDES类型

  • 1.所以我们把表空间的区分为了若干个组,每组开头的一个页面记录着本组内所有的区对应的XDES Entry结构
  • 2.于第一个组的第一个页面有些特殊,因为它也是整个表空间的第一个页面,所以除了记录本组中的所有区对应的XDES Entry结构以外,还记录着表空间的一些整体属性,这个页面的类型就是我们刚刚说完的FSP_HDR类型,整个表空间里只有一个这个类型的页面
  • 3.,我们把之后每个分组的第一个页面的类型定义为XDES,它的结构和FSP_HDR类型是非常相似的--除了少了File Space Header部分之外,也就是除了少了记录表空间整体属性的部分之外,其余的部分是一样一样的

IBUF_BITMAP类型

  • 1.每个分组的第二个页面的类型都是IBUF_BITMAP
  • 2.这种类型的页里边记录了一些有关Change Buffer

INODE类型

  • 1.第一个分组的第三个页面的类型是INODE
  • 2.每个索引定义了两个段,而且为某些特殊功能定义了些特殊的段。为了方便管理,他们又为每个段设计了一个INODE Entry结构
  • 3.一个INODE类型的页面是由这几部分构成的:
  • 4.File Header,List Node for INODE Page List,INODE Entry,Empty Space,File Trailer
  • 5.INODE Entry:对应的段内零散页面的地址以及附属于该段的FREE、NOT_FULL和FULL链表的基节点
  • 6.List Node for INODE Page List:SEG_INODES_FULL链表和SEG_INODES_FREE链表

Segment Header 结构的运用

  • 1.一个索引会产生两个段,分别是叶子节点段和非叶子节点段,而每个段都会对应一个INODE Entry结构,那我们怎么知道某个段对应哪个INODE Entry结构呢
  • 2.也就是INDEX类型的页时有一个Page Header部分的Segment Header 就是记录这些信息的。
  • 3.具体的内容是:Space ID of the INODE Entry,Page Number of the INODE Entry,Byte Offset of the INODE Entry

系统表空间

  • 1.表空间 ID(Space ID)是0
  • 2.系统表空间和独立表空间的前三个页面(页号分别为0、1、2,类型分别是FSP_HDR、IBUF_BITMAP、INODE)的类型是一致的
  • 3.只是页号为3~7的页面是系统表空间特有的:SYS(存储Insert Buffer的头部信息),INDEX(存储Insert Buffer的根页面),TRX_SYS(事务系统的相关信息),SYS(第一个回滚段的页面),SYS(数据字典头部信息)
  • 4.系统表空间的extent 1和extent 2这两个区,也就是页号从64~191这128个页面被称为Doublewrite buffer,也就是双写缓冲区

InnoDB数据字典

元数据是哪些

  • 1.某个表属于哪个表空间,表里边有多少列
  • 2.表对应的每一个列的类型是什么
  • 3.该表有多少索引,每个索引对应哪几个字段,该索引对应的根页面在哪个表空间的哪个页面
  • 4.该表有哪些外键,外键对应哪个表的哪些列
  • 5.某个表空间对应文件系统上文件路径是什么
  • 6.等等

innodb定义了许多内部系统表来记录元数据(也就是数据字典)

  • 1.SYS_TABLES 整个InnoDB存储引擎中所有的表的信息
  • 2.SYS_COLUMNS 整个InnoDB存储引擎中所有的列的信息
  • 3.SYS_INDEXES 整个InnoDB存储引擎中所有的索引的信息
  • 4.SYS_FIELDS 整个InnoDB存储引擎中所有的索引对应的列的信息
  • 5.SYS_FOREIGN 整个InnoDB存储引擎中所有的外键的信息
  • 6.SYS_FOREIGN_COLS 整个InnoDB存储引擎中所有的外键对应列的信息
  • 7.SYS_TABLESPACES 整个InnoDB存储引擎中所有的表空间信息
  • 8.SYS_DATAFILES 整个InnoDB存储引擎中所有的表空间对应文件系统的文件路径信息
  • 9.SYS_VIRTUAL 整个InnoDB存储引擎中所有的虚拟生成列的信息
  • 10.SYS_TABLES、SYS_COLUMNS、SYS_INDEXES、SYS_FIELDS这四个表尤其重要,称之为基本系统表(basic system tables)
  • 11.只要有了上述4个基本系统表,也就意味着可以获取其他系统表以及用户定义的表的所有元数据

Data Dictionary Header页面(数据字典的头部信息)

  • 1.这4个表是表中之表,那这4个表的元数据去哪里获取呢
  • 2.拿出一个固定的页面来记录这4个表的聚簇索引和二级索引对应的B+树位置,这个页面就是页号为7的页面,类型为SYS,记录了Data Dictionary Header
  • 3.Max Row ID:每个表如果没有主键或者唯一索引,那么innodb就生成主键,该属性就是记录整个innodb的Max rou id
  • 4.Max Table ID:InnoDB存储引擎中的所有的表都对应一个唯一的ID,每次新建一个表时,就会把本字段的值作为该表的ID,然后自增本字段的值。
  • 5.Max Index ID:InnoDB存储引擎中的所有的索引都对应一个唯一的ID,每次新建一个索引时,就会把本字段的值作为该索引的ID,然后自增本字段的值。
  • 6.Max Space ID:InnoDB存储引擎中的所有的表空间都对应一个唯一的ID,每次新建一个表空间时,就会把本字段的值作为该表空间的ID,然后自增本字段的值。
  • 7.Root of SYS_TABLES clust index:本字段代表SYS_TABLES表聚簇索引的根页面的页号
  • 8.Root of SYS_TABLE_IDS sec index:本字段代表SYS_TABLES表为ID列建立的二级索引的根页面的页号。
  • 9.Root of SYS_COLUMNS clust index:本字段代表SYS_COLUMNS表聚簇索引的根页面的页号。
  • 10.Root of SYS_INDEXES clust index本字段代表SYS_INDEXES表聚簇索引的根页面的页号。
  • 11.Root of SYS_FIELDS clust index:本字段代表SYS_FIELDS表聚簇索引的根页面的页号。

information_schema系统数据库

  • 1.用户是不能直接访问InnoDB的这些内部系统表的
  • 2.这个数据库里面的表示对上述系统表的一个视图。



posted @ 2021-07-26 22:58  year12  阅读(243)  评论(0编辑  收藏  举报