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.这个数据库里面的表示对上述系统表的一个视图。
Nice to see you all!