【MySQL】存放页面的大池子——InnoDB的表空间

news2024/11/27 10:19:29

1 前置知识回顾

1.1 页面类型

InnoDB是以页为单位管理存储空间的。我们的聚簇索引(也就是完整的表数据)和其他的二级索引都是以B+树的形式保存到表空间中,而B+树中的节点就是数据页,这个数据页的类型名其实是 FIL_PAGE_INDEX。
除了这种存放索引数据的页面类型之外,InnoDB 也针对不同的目的设计了若干种不同类型的页面。
在这里插入图片描述

1.2 页面通用部分

在这里插入图片描述
所有类型的页都会包含下面两个部分:

  • File Header:记录页面的一些通用信息。
  • File Trailer:校验页是否完整,保证页面在从内存刷新到磁盘后内容是相同的。

1.3 数据页结构

数据页(也就是 INDEX 类型的页) 由 7 部分组成,其中 File Header 和 File Trailer 这两个部分是所有类型的页面都通用的。

图片引用自【MySQL系列(4)— InnoDB数据页结构】
其中 File Header、Page Header、File Trailer 的大小是固定的,分别为 38、56、8字节。User Records、Free Space、Page Directory 这些部分为实际的行记录存储空间,因此大小是动态的。

2 表空间——独立表空间结构

2.1 区的概念

表空间中的页过多,不好管理,遂提出区(extent)的概念。
对于16KB的页来说,连续的64个页就是一个区,即,一个区默认占用1MB空间大小。
无论是系统表空间还是独立表空间,都可以看成是由若干个连续的区组成的,每256个区被划分成一组,如图9-2所示:

在这里插入图片描述
每个组的头几个页面的类型是类似的,如图9-3所示。
在这里插入图片描述

2.2 段的概念

2.2.1 为什么引入“区”的概念

场景:
  我们每向表中插入一条记录,本质上就是向该表的聚簇索引以及所有二级索引代表的B+树的节点中插入数据。
  而,B+树中每一层中的页都会形成一个双向链表,如果以页为单位来分配存储空间,双向链表相邻的两个页之间的物理位置可能离得非常远。
  我们知道,使用B+树来减少记录的扫描行数的过程是通过一些搜索条件到B+树的叶子节点中定位到第一条符合该条件的记录(对于全表扫描来说,就是定位到第一个叶子节点的第一条记录),然后沿着由记录组成的单向链表以及由数据页组成的双向链表一直向后扫描就可以了。
  但是,如果双向链表中相邻的两个页的物理位置不连续,对于传统的机械硬盘来说,需要重新定位磁头位置,也就是会产生随机I/O,这样会影响磁盘的性能。
  所以,应尽量(页面链表中相邻的页的页号不连续也可,只是略影响性能)让页面链表中相邻的页的物理位置也相邻,这样在扫描叶子节点中大量的记录时,才可以使用顺序I/O。

总结:

  • 区:一个区就是在物理位置上连续的64个页(区里页面的页号都是连续的)。
  • 引入“区”的目的: 消除随机I/O,提升性能。
  • 详述:在表中的数据量很大时,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区为单位进行分配。甚至在表中的数据非常非常多的时候,可以一次性分配多个连续的区。虽然这可能造成一点点空间的浪费(数据不足以填充满整个区)。但是从性能角度看,可以消除很多的随机 I/O——功大于过嘛!

2.2.2 为什么引入“段”的概念

  在使用B+树执行查询时,只是在扫描叶子节点的记录,而如果不区分叶子节点和非叶子节点,统统把节点代表的页面放到申请到的区中,扫描效果就大打折扣了。所以,设计 lnnoDB 的大叔对 B+ 树的叶子节点和非叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区。存放叶子节点的区的集合就算是一个段 (segment),存放非叶子节点的区的集合也算是一个段。 也就是说一个索引会生成两个段:一个叶子节点段和一个非叶子节点段。

2.2.2 为什么引入“碎片区”的概念

  默认情况下,一个使用 lnnoDB 存储引擎的表只有一个聚簇索引,一个索引会生成两个段。而段是以区为单位申请存储空间的,一个区默认占用 1MB 存储空间。
  所以,默认情况下一个只存放了几条记录的小表也需要 2MB 的存储空间么? 以后每次添加一个索引都要多申请 2MB的存储空间么?这对于存储记录比较少的表来说简直是天大的浪费。
  现在为了考虑”以完整的区为单位分配给某个段时,对于数据量较小的表来说太浪费存储空间" 这种情况,提出了碎片(fragment)区 的概念。

2.2.3 碎片区

即,在一个碎片区中,并不是所有的页都是为了存储同一个段的数据而存在的,碎片区中的页可以用于不同的目的,比如,有些页属于段A,有些页属于段B,有些页甚至不属于任何段。
碎片区直属于表空间,并不属于任何一个段。所以,此后为每个段分配存储空间的策略如下:

  • 在刚开始向表中插入数据时,段是从某个碎片区以单个页面为单位来分配存储空间的;
  • 当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间(原先占用的碎片区页面并不会被复制到新申请的完整的区中)。

  所以,段现在不能仅定义为某些区的集合,更精确的说,应该是某些零散的页面以及一些完整的区的集合。
  除了索引的叶子节点段和非叶子节点段之外,InnoDB中还有为存储一些特殊的数据而定义的段,比如回滚段。

2.3 区的分类

表空间是由若干个区组成的。这些区大致可以分为4种类型。

  • 空闲的区:现在还没有用到这个区中的任何页面.
  • 有剩余空闲页面的碎片区:表示碎片区中还有可被分配的空闲页面.
  • 没有剩余空闲页面的碎片区:表示碎片区中的所有页面都被分配使用,没有空闲页面.
  • 附属于某个段的区: 我们知道,每一个索引都可以分为叶子节点段和非叶子节点段。除此之外,lnnoDB 会另外定义一些特殊用途的段,当这些段中的数据量很大时,将使用区作为基本的分配单位,这些区中的页面完全用于存储该段中的数据(而碎片区可以存储属于不同段的数据)。

这4种类型的区也可以称为区的4种状态(State),设计 lnnoDB 的大叔为这4种状态的区定义了特定的名词,如表 9-3 所示。
在这里插入图片描述

强调:

  • 处于 FREE、FREE_FRAG 以及 FULL_FRAG 这3种状态的区都是独立的,直属于表空间;
  • 而处于 FSEG 状态的区是附属于某个段的。

2.3.1 XDES Entry 链表

每个区都对应一个 XDES Entry 结构,这个结构中存储了一些与这个区有关的属性。这些区可以被分为下面几种类型。

  • 空闲的区:这些区会被加入到 FREE 链表。
  • 有剩余空闲页面的碎片区:这些区会被加入到 FREE_FRAG 链表。
  • 没有剩余空闲页面的碎片区:这些区会被加入到 FULL_FRAG 链表。
  • 附属于某个段的区:每个段所属的区又会被组织成下面几种链表。
    • FREE 链表:在同一个段中,所有页面都是空闲页面的区对应的 XDES Entry 结构会被加入到这个链表。
    • NOT_FULL 链表:在同一个段中,仍有空闲页面的区对应的 XDES Entry 结构会被加入到这个链表。
    • FULL 链表:在同一个段中,已经没有空闲页面的区对应的 XDES Entry 结构会被加入到这个链表。
  • 举例
      再强调一遍,每一个索引都对应两个段,每个段都会维护上述3个链表。比如下面这个表:
CREATE TABLE t(
	c1 INT NOT NULL AUTO_INCREMENT,
	c2 VARCHAR(100),
	c3 VARCHAR(100),
	PRIMARY KEY(c1),
	KEY idx_c2(c2)
)ENGINE=InnoDB;

  表 t 共有两个索引:一个聚簇索引和一个二级索引 idx_c2。所以这个表共有4个段,每个段都会维护上述3个链表,总共是12个链表。再加上直属于表空间的3个链表,整个独立表空间共需要维护15个链表。

2.3.2 链表基节点 ( List Base Node )

问题: 我们们怎么找到这些链表呢?或者说怎么找到某个链表的头节点或者尾节点在表空间中的位置呢?
解决:设计了一个名为 List Base Node (链表基节点) 的结构。这个结构中包含了链表的头节点和尾节点的指针以及这个链表中包含了多少个节点的信息。
在这里插入图片描述
前面介绍的每个链表都对应这么 List Base Node 结构,其中.

  • List Length: 表明该链表一共有多少个节点 ;
  • First Node Page Number 和 First Node Offset :表明该链表的头节点在表空间中的位置;
  • Last Node Page Number 和 Last Node Offset :表明该链表的尾节点在表空间中的位置。

我们一般把某个链表对应的 List Base Node 结构放置在表空间中的固定位置。这样就可以很容易地定位某个链表了。

2.3.3 链表小结

综上所述,

  • 表空间是由若干个区组成的,每个区都对应一个 XDES Entry 结构 ,直属于表空间的区对应的 XDES Entry 结构可以分成 FREE、FREE_FRAG 和 FULL_FRAG 这3个链表。
  • 每个段可以拥有若干个区,每个段中的区对应的 XDES Entry 结构可以构成 FREE、NOT_FULL 和 FULL 这三个链表。每个链表都对应一个 List Base Node 结构,这个结构中记录了链表的头尾节点的位置以及该链表中包含的节点数。

正是因为这些链表的存在,管理这些区才变成了一件相当容易的事情。

2.4 段的结构

段:是一个逻辑上的概念,某些零散的页面以及一些完整的区的集合。
像每个区都有对应的 XDES Entry 来记录这个区中的属性一样,设计 InnoDB 的大叔为每个段都定义了一个 INODE Entry 结构来记录这个段中的属性。
强调:每个段都会对应一个 INODE Entry 结构,该结构中存储了一些与这个段有关的属性。
在这里插入图片描述
INODE Entry 结构各个部分含义如下:

  • Segment ID :这个 INODE Entry 结构对应的段的编号(ID)。
  • NOT_FULL_N_USED:在 NOT_FULL链表中已经使用了多少个页面。
  • 3个List Base Node: 分别为段的 FREE链表、NOT_FULL链表、FULL链表定义了 List Base Node, 这样当想查找某个段的某个链表的头节点和尾节点时,可以直接到这个部分找到对应链表的 List Base Node。
  • Magic Number:用来标记这个 INODE Entry 是否已经被初始化(即把各个字段的值都填进去了)。如果这个数字的值是 97,937,874,表明该 INODE Entry已经被初始化,否则没有被初始化(不用纠结值 97,937, 874有啥特殊含义,这是人家规定的)。
  • Fragment Array Entry: 段是一些零散页面和一些完整的区的集合,每个Fragment Array Entry 结构都对应着一个零散的页面,这个结构一共4字节,表示一个零散页面的页号。

概念:

  • 页: 是InnoDB存储引擎管理数据库的最小磁盘单位,一个页的大小一般是16KB。一次至少读取一页的数据到内存,或者刷新一页的数据到磁盘。
  • 数据页:FIL_PAGE_INDEX类型的页,B+树中的节点就是数据页。
  • 区:一个区就是在物理位置上连续的64个页(区里页面的页号都是连续的)。
  • 段:是一个逻辑上的概念,某些零散的页面以及一些完整的区的集合。
  • XDES Entry 结构:记录区中的属性。(每个区都对应一个 XDES Entry 结构,存储了一些与这个区有关的属性。)
  • INODE Entry 结构:记录段中的属性。(每个段都会对应一个 INODE Entry 结构,该结构中存储了一些与这个段有关的属性。)
  • List Base Node (链表基节点):这个结构中包含了链表的头节点和尾节点的指针以及这个链表中包含了多少个节点的信息。

3 表空间——系统表空间结构

  系统表空间的结构与独立表空间基本类似,只不过由于整个 MySQL 进程只有一个系统表空间,系统表空间中需要记录一些与整个系统相关的信息,所以会比独立表空间多出一些用来记录这些信息的页面。因为这个系统表空间最重要,相当于所有表空间的 “带头大哥" ,所以,它的表空间 ID (Space ID) 是0。

3.1 系统表空间的整体结构

  与独立表空间相比,系统表空间有一个非常明显的不同之处,就是在表空间开头有许多记录整个系统属性的页面,如图 9-13 所示.
在这里插入图片描述
可以看到,系统表空间和独立表空间的前3个页面(页号分别为0、1、2,类型分别是
FSP_HDR、 IBUF_BITMAP 、INODE) 的类型是一致的,但是页号为 3~7 的页面是系统表空
间特有的。
在这里插入图片描述
除了这几个记录系统属性的页面之外,系统表空间的 extent 1 和 extent 2 这两个区,也就是页号从 64 ~ 191 的这 128 个页面称为 Doublewrite Buffer (双写缓冲区)。 上述大部分知识都
涉及事务和多版本控制的问题。

参考资料:
https://juejin.cn/post/6974225353371975693
——读书笔记,摘自《MySQL是怎样运行的》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/471260.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS手撕代码系列【手写实现Promise.all】

Promise.all() 方法接收一个 Promise 对象数组作为参数,返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都成功时才会成功,其中一个 Promise 对象失败时,则该 Promise 对象立即失败。 本篇博客将手写实现 Promise.all() 方…

初始 Ajax

文章目录 一、服务器的基本概念1、客户端与服务器2、url地址3、客户端与服务器的通信过程4、服务器对外提供资源5、资源的请求方式 二、初始 Ajax1、了解Ajax2、JQuery中的Ajax(1)$.get()函数的用法(2)$.post()函数的语法&#xf…

国民技术N32G430开发笔记(7)- Gpio EXTI中断的使用

GPIO EXTI中断的使用 1、N32G430C8L7_STB板卡带有三个用户按键,我们初始化key1 key2 按键,当按键按下时,在中断处理函数里输出我们的打印信息。 2、根据芯片手册上N32G430C8L7有24 条中断线,16条分配给GPIO使用,其余八…

中国移动发布COCA软硬一体片上计算架构,引领云计算市场下一个黄金十年

当前,数字经济发展已经成为改变全球竞争格局的关键力量,随着算力成为数字经济新引擎,算力规模持续增长,算力结构发生改变。主动拥抱智算浪潮,持续输出优质算力支撑数字中国建设,适配泛在化、异构化算力推动…

JavaWeb之过滤器Filter(通俗易懂版)

今天开发遇到了,简单记录一下! 简介:Filter是JavaWeb三大组件之一(Servlet程序、Listener监听器、Filter过滤器) 作用:既可以对请求进行拦截,也可以对响应进行处理。 1、Filter中的三个方法 …

【无标题】c++异常机制的一些总结以及思考

在谈及c处理异常机制的方法之前我们不妨来回顾一下c语言是如何应对这块的。 终止程序,如assert,缺陷:用户难以接受。如发生内存错误,除0错误时就会终止程序。 返回错误码,缺陷:需要程序员自己去查找对应的…

深兰科技再获欧洲订单,中国造智能机器人出海“服务”西班牙

近日,经过包含关键技术、场景适配性、任务完成效率、产品操作便捷度等考核标准在内多轮综合对比,深兰科技突出重围,斩获西班牙一笔价值百万的智能室内清洁机器人采购订单。 多重问题显示,欧洲清洁市场亟待科技赋能 在当前的经济形…

VUE初级知识点总结

前言 近几年随着HTML5的普及,原来的jsp逐渐在被淘汰,而vue成了很多前端开发者的心仪的js框架,因为它相对于其他两大框架(Angula、React)更简单易学,当然了这里的简单易学指的是上手快,在不知道…

7.3 股票分析(project)

目录 第1关:涨幅和成交量 第2关 涨幅与最高价 第3关 跌幅与最低价 本关任务:完成涨幅和成交量股票分析。 相关知识 1.sorted()函数 2.集合运算 sorted()函数 sorted() 函数对所有可迭代的对象进行排序操作。 sorted(iterable, keyNone, reverseFal…

Linxu下性能指标采集工具之nmon工具的使用

前言 近期在测试JefLogTail,由于JefLogTail使用的是轮询的方式来监听文件夹,所以对cpu的消耗可能会高一些,所以在测试的时候着重关注CPU,Linux下查看CPU信息一般采用top命令来实时观察,但是这种对于只是通过观察数据的变化来评估…

跟着我学习 AI丨初识 AI

人工智能(AI)是一种模拟人类思维和行为的计算机技术,通过学习、推理和自我修正等方式,使机器能够模拟人类智能,并具有一定的自主决策能力。AI 可以被用于解决各种难题,如自动化、机器人、自动驾驶、语音识别…

【LeetCode】53. 最大子数组和

53. 最大子数组和(中等) 思路 这道题的状态设计和状态转移和 300. 最长递增子序列 类似。但是这里要求的是连续子数组,和子序列不同。 状态定义 首先定义 dp[i]:以 nums[i] 结尾的具有最大和的连续子数组。 状态转移方程 根据…

idea项目打成war包,出现路径问题(已解决)

参考文档: https://www.cnblogs.com/huaixiaonian/p/10521460.html 解释说明: 什么路径问题呢,就比如你们合作开发了一个项目,然后打成了一个war包,然后路径以前的是这种的 http://localhost:8080 就可以直接运行&…

《计算机网络——自顶向下方法》精炼

“An investment in knowledge pays the best interest.” - Benjamin 文章目录 分布式散列表(键-值)对散列函数逻辑上的实现环形DHT对等方扰动对等方离开对等方加入 UDP套接字编程客户端代码服务器端代码 分布式散列表 分布式散列表是一种数据库。集中…

锁相环的工作原理

锁相环是一个能够比较输入与输出信号相位差的反馈系统,利用外部输入的参考信号控制环路内部的振荡信号的频率和相位,使振荡信号同步至参考信号。 问题:既然是利用外部的参考时钟控制内部的振荡信号频率和相位使内部信号同步至外部参考,那为什么不直接用导线将外部参考信号…

微服务监控系统选型:Zabbix、Open-Falcon、Prometheus

监控系统的 7 大作用 实时采集监控数据:包括硬件、操作系统、中间件、应用程序等各个维度的数据。实时反馈监控状态:通过对采集的数据进行多维度统计和可视化展示,能实时体现监控对象的状态是正常还是异常。预知故障和告警:能够提…

08 【Sass语法介绍-混合指令】

1.前言 混合指令在 Sass 中也是一个比较常用的指令,在前面我们讲解的内容中有编写过混合指令 mixin ,本节我们将详细讲解混合指令 mixin 的语法包括定义混合指令和引用混合指令等等,混合指令同样非常好用,我们一起来学习它吧。 …

python 离线安装pyinstaller

Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirrorhttps://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/下载各类anaconda Archived: Python Extension Packages for Windows - Christoph Gohlke (uci.edu)https://www.lfd.uci.edu/~g…

OpenGL(二)—— Hello World

目录 一、前言 二、渲染 三、GLSL 3.1 数据类型 3.2 编程步骤 四、渲染窗口 五、渲染三角形 5.1 顶点输入 5.2 顶点着色器 5.3 片段着色器 5.4 着色器链接 5.5 顶点属性 5.6 VAO管理顶点属性 5.7 画图 六、渲染四边形 6.1 元素缓冲对象EBO 6.2 运行 一、前言 G…

hbuilder打包IOS上线APP流程

iOS 系统打包流程 1. 创建唯一标识符 (1) 首先,申请苹果开发者账号。没有苹果开发者账号是无法进行 ios 打包上线的。 (2) 进入链接: https://developer.apple.com 这个网址,点击“account”并输入苹果开…