首页 > 其他分享 >InnoDB表空间

InnoDB表空间

时间:2023-04-23 10:38:45浏览次数:28  
标签:SYS write InnoDB 空间 数据 页面


表空间是一个抽象的概念,对于系统表空间来说,对应着文件系统中一个或多个实际文件;对于每个独立表空间来说,对应着文件系统中一个名为表名.ibd的实际文件。大家可以把表空间想象成被切分为许许多多个页的池子,当我们想为某个表插入一条记录的时候,就从池子中捞出一个对应的页来把数据写进去。

再回忆一次,InnoDB是以页为单位管理存储空间的,我们的聚簇索引(也就是完整的表数据)和其他的二级索引都是以B+树的形式保存到表空间的,而B+树的节点就是数据页。

任何类型的页都有File Header这个部分,File Header中专门的地方(FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID)保存页属于哪个表空间,同时表空间中的每一个页都对应着一个页号(FIL_PAGE_OFFSET),这个页号由4 个字节组成,也就是32个比特位,所以一个表空间最多可以拥有2³²个页,如果按照页的默认大小16KB来算,一个表空间最多支持64TB的数据。

独立表空间结构

区(extent)

表空间中的页可以达到2³²个页,实在是太多了,为了更好的管理这些页面,InnoDB中还有一个区(英文名:extent)的概念。对于16KB的页来说,连续的64个页就是一个区,也就是说一个区默认占用1MB空间大小。

不论是系统表空间还是独立表空间,都可以看成是由若干个区组成的,每256个区又被划分成一个组。

第一个组最开始的3个页面的类型是固定的:用来登记整个表空间的一些整体属性以及本组所有的区被称为FSP_HDR,也就是extent0~extent255这256个区,整个表空间只有一个FSP_HDR。

其余各组最开始的2个页面的类型是固定的,一个XDES类型,用来登记本组256个区的属性,FSP_HDR类型的页面其实和XDES类型的页面的作用类似,只不过FSP_HDR类型的页面还会额外存储一些表空间的属性。

引入区的主要目的是什么?我们每向表中插入一条记录,本质上就是向该表的聚簇索引以及所有二级索引代表的B+树的节点中插入数据。而B+树的每一层中的页都会形成一个双向链表,如果是以页为单位来分配存储空间的话,双向链表相邻的两个页之间的物理位置可能离得非常远。

我们介绍B+树索引的适用场景的时候特别提到范围查询只需要定位到最左边的记录和最右边的记录,然后沿着双向链表一直扫描就可以了,而如果链表中相邻的两个页物理位置离得非常远,就是所谓的随机I/O。再一次强调,磁盘的速度和内存的速度差了好几个数量级,随机I/O是非常慢的,所以我们应该尽量让链表中相邻的页的物理位置也相邻,这样进行范围查询的时候才可以使用所谓的顺序I/O。

一个区就是在物理位置上连续的64个页。在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区为单位分配,甚至在表中的数据十分非常特别多的时候,可以一次性分配多个连续的区,从性能角度看,可以消除很多的随机I/O。

段(segment)

我们提到的范围查询,其实是对B+树叶子节点中的记录进行顺序扫描,而如果不区分叶子节点和非叶子节点,统统把节点代表的页面放到申请到的区中的话,进行范围扫描的效果就大打折扣了。所以InnoDB对B+树的叶子节点和非叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区。存放叶子节点的区的集合就算是一个段(segment),存放非叶子节点的区的集合也算是一个段。也就是说一个索引会生成2 个段,一个叶子节点段,一个非叶子节点段。

段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念。

InnoDB表空间_innodb

系统表空间

整体结构

系统表空间的结构和独立表空间基本类似,只不过由于整个MySQL进程只有一个系统表空间,在系统表空间中会额外记录一些有关整个系统信息的页面,所以会比独立表空间多出一些记录这些信息的页面,相当于是表空间之首,所以它的表空间ID(Space ID)是0。

系统表空间和独立表空间的前三个页面的类型是一致的,只是页号为3~7的页面是系统表空间特有的。分别包括:

页号

页面类型

英文描述

描述

3

SYS

Insert Buffer Header

存储Insert Buffer的头部信息

4

INDEX

Insert Buffer Root

存储Insert Buffer的根页面

5

TRX_SYS

Transction System

事务系统的相关信息

6

SYS

First Rollback Segment

第一个回滚段的页面

7

SYS

Data Dictionary Header

数据字典头部信息

系统表空间的extent 1和extent 2这两个区,也就是页号从64~191这128个页面被称为Double write buffer,也就是双写缓冲区。

双写缓冲区/双写机制

双写缓冲区/双写机制是InnoDB的三大特性之一,还有两个是Buffer Pool、自适应Hash索引。

它是一种特殊文件flush技术,带给InnoDB存储引擎的是数据页的可靠性。

它的作用是,在把页写到数据文件之前,InnoDB先把它们写到一个叫double write buffer(双写缓冲区)的连续区域内,在写double write buffer完成后,InnoDB才会把页写到数据文件的适当的位置。如果在写页的过程中发生意外崩溃,InnoDB在稍后的恢复过程中在double write buffer中找到完好的page副本用于恢复。

所以,虽然叫双写缓冲区,但是这个缓冲区不仅在内存中有,更多的是属于MySQL的系统表空间,属于磁盘文件的一部分。那为什么要引入一个双写机制呢?

InnoDB的页大小一般是16KB,其数据校验也是针对这16KB来计算的,将数据写入到磁盘是以页为单位进行操作的。而操作系统写文件是以4KB作为单位的,那么每写一个InnoDB的页到磁盘上,操作系统需要写4个块。而计算机硬件和操作系统,在极端情况下(比如断电)往往并不能保证这一操作的原子性,16K的数据,写入4K时,发生了系统断电或系统崩溃,只有一部分写是成功的,这种情况下会产生partial page write(部分页写入)问题。这时页数据出现不一样的情形,从而形成一个"断裂"的页,使数据产生混乱。在InnoDB存储引擎未使用double write技术前,曾经出现过因为部分写失效而导致数据丢失的情况。

double write buffer是InnoDB在表空间上的128个页(2个区,extend1和extend2),大小是2MB。为了解决部分页写入问题,当MySQL将脏数据flush到数据文件的时候, 先使用memcopy将脏数据复制到内存中的一个区域(也是2M),之后通过这个内存区域再分2次,每次写入1MB到系统表空间,然后马上调用fsync函数,同步到磁盘上。在这个过程中是顺序写(顺序IO),开销并不大,在完成double write写入后,再将数据写入各数据文件文件,这时是随机写入(随机IO)。

所以在正常的情况下, MySQL写数据页时,会写两遍到磁盘上,第一遍是写到double write buffer,第二遍是写到真正的数据文件中。如果发生了极端情况(断电),InnoDB再次启动后,发现了一个页数据已经损坏,那么此时就可以从double write buffer中进行数据恢复了。

前面说过,位于系统表空间上的double write buffer实际上也是一个文件,写系统表空间会导致系统有更多的fsync操作, 而硬盘的fsync性能因素会降低MySQL的整体性能。不过在存储上,double write是在一个连续的存储空间,所以硬盘在写数据的时候是顺序写,而不是随机写,这样性能影响不大,相比不双写,降低了大概5-10%左右。

所以,在一些情况下可以关闭double write以获取更高的性能。比如在slave上可以关闭,因为即使出现了partial page write问题,数据还是可以从中继日志中恢复。比如某些文件系统ZFS本身有些文件系统本身就提供了部分写失效的防范机制,也可以关闭。

在数据库异常关闭的情况下启动时,都会做数据库恢复(redo)操作,恢复的过程中,数据库都会检查页面是不是合法(校验等等),如果发现一个页面校验结果不一致,则此时会用到双写这个功能。

有经验的同学也许会想到,如果发生写失效,可以通过重做日志(Redo Log)进行恢复啊!但是要注意,重做日志中记录的是对页的物理操作,如偏移量800,写’ aaaa’记录,而不是页面的全量记录,而如果发生partial page write(部分页写入)问题时,出现问题的是未修改过的数据,此时重做日志(Redo Log)无能为力。

写double write buffer成功了,这个问题就不用担心了。如果是写doublewrite buffer本身失败,那么这些数据不会被写到磁盘,InnoDB此时会从磁盘载入原始的数据,然后通过InnoDB的事务日志来计算出正确的数据,重新写入到doublewrite buffer,这个速度就比较慢了。如果double write buffer写成功的话,但是写数据文件失败,innodb就不用通过事务日志来计算了,而是直接用double write buffer的数据再写一遍,速度上会快很多。

总体来说,double write buffer的作用有两个:提高innodb把缓存的数据写到硬盘这个过程的安全性;间接的好处就是,innodb的事务日志不需要包含所有数据的前后映像,而是二进制变化量,这可以节省大量的IO。

InnoDB 数据字典(Data Dictionary Header)

我们平时使用INSERT语句向表中插入的那些记录称之为用户数据,MySQL只是作为一个软件来为我们来保管这些数据,提供方便的增删改查接口而已。但是每当我们向一个表中插入一条记录的时候,MySQL先要校验一下插入语句对应的表存不存在,插入的列和表中的列是否符合,如果语法没有问题的话,还需要知道该表的聚簇索引和所有二级索引对应的根页面是哪个表空间的哪个页面,然后把记录插入对应索引的B+树中。所以说,MySQL除了保存着我们插入的用户数据之外,还需要保存许多额外的信息,比方说:某个表属于哪个表空间,表里边有多少列,表对应的每一个列的类型是什么,该表有多少索引,每个索引对应哪几个字段,该索引对应的根页面在哪个表空间的哪个页面,该表有哪些外键,外键对应哪个表的哪些列,某个表空间对应文件系统上文件路径是什么。上述这些数据并不是我们使用INSERT语句插入的用户数据,实际上是为了更好的管理我们这些用户数据而不得已引入的一些额外数据,这些数据也称为元数据。InnoDB存储引擎特意定义了一些列的内部系统表(internal system table)来记录这些这些元数据:

表名

描述

SYS_TABLES

整个InnoDB 存储引擎中所有的表的信息

SYS_COLUMNS

整个InnoDB 存储引擎中所有的列的信息

SYS_INDEXES

整个InnoDB 存储引擎中所有的索引的信息

SYS_FIELDS

整个InnoDB 存储引擎中所有的索引对应的列的信息

SYS_FOREIGN

整个InnoDB 存储引擎中所有的外键的信息

SYS_FOREIGN_COLS

整个InnoDB 存储引擎中所有的外键对应列的信息

SYS_TABLESPACES

整个InnoDB 存储引擎中所有的表空间信息

SYS_DATAFILES

整个InnoDB 存储引擎中所有的表空间对应文件系统的文件路径信息

SYS_VIRTUAL

整个InnoDB 存储引擎中所有的虚拟生成列的信息

这些系统表也被称为数据字典,它们都是以B+树的形式保存在系统表空间的某些页面中,其中SYS_TABLES、SYS_COLUMNS、SYS_INDEXES、SYS_FIELDS这四个表尤其重要,称之为基本系统表。

这4个表是表中之表,那这4个表的元数据去哪里获取呢?只能把这4个表的元数据,就是它们有哪些列、哪些索引等信息硬编码到代码中,然后InnoDB的又拿出一个固定的页面来记录这4个表的聚簇索引和二级索引对应的B+树位置,这个页面就是页号为7的页面Data Dictionary Header,类型为SYS,记录了数据字典的头部信息。除了这4个表的5个索引的根页面信息外,这个页号为7的页面还记录了整个InnoDB存储引擎的一些全局属性,比如Row ID。数据字典头部信息中有个Max Row ID字段,我们说过如果我们不显式的为表定义主键,而且表中也没有UNIQUE索引,那么InnoDB存储引擎会默认为我们生成一个名为row_id的列作为主键。因为它是主键,所以每条记录的row_id列的值不能重复。原则上只要一个表中的row_id列不重复就可以了,也就是说表a和表b拥有一样的row_id 列也没啥关系,不过InnoDB只提供了这个Max Row ID字段,不论哪个拥有row_id 列的表插入一条记录时,该记录的row_id 列的值就是MaxRow ID对应的值,然后再把Max Row ID对应的值加1,也就是说这个Max Row ID是全局共享的。

用户是不能直接访问InnoDB的这些内部系统表的,除非你直接去解析系统表空间对应文件系统上的文件。不过InnoDB考虑到查看这些表的内容可能有助于大家分析问题,所以在系统数据库information_schema中提供了一些以innodb_sys开头的表:

在information_schema数据库中的这些以INNODB_SYS开头的表并不是真正的内部系统表,而是在存储引擎启动时读取这些以SYS开头的系统表,然后填充到这些以INNODB_SYS开头的表中。


标签:SYS,write,InnoDB,空间,数据,页面
From: https://blog.51cto.com/u_6784072/6216450

相关文章

  • InnoDB索引页结构
    InnoDB是一个将表中的数据存储到磁盘上的存储引擎,所以即使关机后重启我们的数据还是存在的。而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上。而我们知道读写磁盘的速度非常慢,和内存读写差......
  • 【MySQL】InnoDB中的GAP锁详解
    测试数据:CREATETABLE`lock_test`(`a`int(11)NOTNULLAUTO_INCREMENT,`b`int(11)NOTNULL,`c`int(11)NOTNULL,`d`int(11)NOTNULL,PRIMARYKEY(`a`),UNIQUEKEY`idx_b`(`b`),KEY`idx_c`(`c`))ENGINE=InnoDBDEFAULTCHARSET=latin1;IN......
  • InnoDB之Undo log
    事务回滚的需求事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做。但是偏偏有时候事务执行到一半会出现一些情况,比如:1、事务执行过程中可能遇到各种错误,比如服务器本身的错误,操作系统错误,甚至是突然断电导致的错误。2、程序员可以在事务执行过程中手动输入ROLLBACK......
  • JTS空间坐标Geometry使用
    Geomtery子类图创建GeometryGeometryFactorygeometryFactory=JTSFactoryFinder.getGeometryFactory();//点Coordinatecoord=newCoordinate(1,1);Pointpoint=geometryFactory.createPoint(coord);//线Coordinate[]coordinates=newCoordinate[]{newC......
  • 16.InnoDB Cluster 简单搭建
    1.主机规划列表、iphostname主机角色安装软件192.168.10.134db01mastermysql、myshell192.168.10.130db02slavemysql、myshell192.168.10.131db03slavemysql、myshell192.168.10.132db04managermyshell、myrouter      2.......
  • 空间点、直线、平面之间的位置关系
    平面平面内有无数个点,平面可以看成点的集合,点\(A\)在平面\(\alpha\)内,记作\(\alpha\inA\);点\(B\)在平面\(\alpha\)外,记作\(B\notin\alpha\)。公理\(1\):如果一条直线上的两点在一个平面内,那么这条直线在此平面内。符号表示:\(A\inl,B\inl\),且\(A\in\alpha,......
  • docker mysql 错误跟innodb有关
     错误截图 dockerps-a查看所有容器  容器开启失败,进入也失败 原因两个数据的文件冲突了,将你需要启动的那个数据库里面的这个干掉(即删除这两个文件)解决方式:备份(或者移除)两个文件ib_logfile0ib_logfile1 查找文件所在目录find/-nameib_logfile0......
  • k3s 基础 —— 配置 traefik ingress 跨命名空间访问
    新增配置文件/var/lib/rancher/k3s/server/manifests/traefik-config.yaml参考apiVersion:helm.cattle.io/v1kind:HelmChartConfigmetadata:name:traefiknamespace:kube-systemspec:valuesContent:|-globalArguments:-"--providers.kubernetescrd......
  • 磁盘空间占满问题---------------inode资源问题
    LINUX实战--inode资源问题原创 梦想家-kk 技术梦想家 2023-01-1719:30 发表于福建收录于合集#linux9个 LINUX操作系统 1问题现象目录中创建文件提示本地空间不足,但是通过df-Th发现本地目录下仍有剩余空间  2什么是inode在linux操作系统中,实际每......
  • C#基础 namespace 命名空间嵌套,各空间内成员相互独立
     .NETFramework:4.7.2       IDE:VisualStudioCommunity2019        OS:Windows10x64    typesetting:Markdown codeusingSystem;namespaceSpaceOuter{classStudent{publicintnum=0;}namespaceSpaceI......