【InnoDB数据存储结构】第1章节:数据页存储结构

目录结构

之前整篇文章太长,阅读体验不好,将其拆分为几个子篇章。

本篇章讲解 InnoDB 数据页的存储结构。

数据的存储结构

索引是在存储引擎中实现的,MySQL 服务器上的 存储引擎负责对表数据的读取和写入。

但是不同存储引擎对 数据存放格式一般是不同的,甚至有的存储引擎都不用磁盘存储数据,比如:Memory。

MySQL 默认的存储引擎是 InnoDB,所以下文均以 InnoDB 展开叙述。

MySQL 数据存储目录

先看下 MySQL 数据库的文件存放在哪个目录中?

使用命令:

show variables like 'datadir';select @@datadir

这个是修改后的目录路径,实际上 MySQL 默认的存储路径为:/var/lib/mysql

我们每创建一个数据库 database_name,这个目录下(包括自定义的)就会创建一个以 数据库名为名的目录,然后里面存储表结构和表数据文件。

Innodb 存储引擎创建的任何一张表的都会有两个文件:

  • test_table.frm:存储 表结构的文件,保存表的原数据信息
  • test_table.ibd:存储 表数据的文件,表数据既可以存储共享表空间文件中(ibdata1中),也可以存储在独占表空间中(后缀 .idb中),是否存储在独占表中,可以通过参数 innodb_file_per_table控制,设置为 1,则会存储在独占表空间中,从 MySQL 5.6.6 版本之后,innodb_file_per_table默认值就为 1 了,因此此后的版本,表数据都是存储在独占表中的。

表数据文件存储结构是怎么样的?

表空间由段(segment)、区(extent)、页(page)、行(row)组成,InnoDB存储引擎的逻辑存储结构大致如下图(图源:小林 coding):

这个图很是形象,也很到位了。

咱从下往上看,介绍下各名词的含义:

  • **行(row):**数据库中的数据都是按行(row)存储的,行记录(是统称)根据不同的 行格式,有不同的存储结构。下文我们重点介绍 InnoDB 存储引擎的行格式。
  • **页(page):**记录是按行存储的,但是数据库的读取并不是以 单位,而是以 为单位,每页的大小为 16KB,否则读取一次只能读取一行数据(也就是一次 I/O 操作),只能处理一行数据,效率太低了。
  • **区(extent):**B+Tree 的每一层节点之间都是通过双向链表链接的,以页为单位,相邻的两个页之间位置并不是连续的,可能离的非常远,那么数据量大的情况在查询的时候就会产生大量的随机 I/O 操作(效率低)。为了解决这个问题,为某个索引分配空间的时候按照 为单位,一个区的大小为 1MB,对于 16KB大小的页来说,连续的 64 个页划分为一个 ,这样就使得相邻的页的物理位置也是相邻的,就可以使用顺序 I/O 了。
  • **段(segment):**表空间由多个段组成,段时由多个区组成。段一般分为数据段、索引段和回滚段等
    • 索引段:存放 B+Tree 非叶子节点区的集合
    • 数据段:存放 B+Tree 叶子节点区的集合
    • 回滚段:存放回滚数据区的集合(MVCC 就是利用了回滚段实现了多版本查询控制)

再对比下康师傅画的图(原理是一样的):

补充:

  • 段是数据库中的分配单位

  • 不同类型的数据库对象以不同的段形式存储

    • 创建一张表默认会创建一个表段(数据段)
    • 创建一个索引默认会创建一个索引段
  • 表空间(Tablespace) 是一个逻辑容器,表空间存储的对象是段,在一个空间中可以由一个段或多个段,但是一个段只能属于一个表空间。

  • 数据库是由一个或多个表空间组成,表空间从管理上可以划分为 系统表空间用户表空间撤销表空间临时表空间等。

  • 系统表空间/var/lib/mysql/下有一个文件 ibdata1文件,这个文件就被称为 系统表空间。加入创建一个表 test_table:

    • 表结构的元数据会存储在 test_table.frm
    • 如果采用 系统表空间 模式,数据信息和索引信息都会存储在 ibdata1
    • 如果采用 独立表空间 模式,数据信息和索引信息都会存储在 test_table.ibd

根据上图,我们对 InnoDB 数据的存储结构有了大致的了解,下面咱接着来。

数据页结构

了解行记录存储格式之前,我们先了解下页的内部存储构造。

InnoDB 默认将数据划分为若干个页,页的大小默认为 16KB

在数据库中,不论是读取一行还是读取多行数据,都是将这些行所在的页一次性从磁盘中加载到内存中(一次 I/O 操作),数据库 I/O 操作的最小单位就是页 。

查看 InnoDB 存储引擎一个数据页的大小:

show variables like '%innodb_page_size%'
或者
select @@innodb_page_size

扩展:

SQL Server 中页的大小为 8KB,而在 Oracle 中我们用术语 块 (Block)来代表 ,Oracle 支持的块大小有:2KB、4KB、8KB、32KB 和 64KB。

页的内部结构

这 7 个部分作用分别如下所示:

归类为三大部分:

第 1 部分:文件头和文件尾

File Header(文件头)

描述各种页的通用信息(比如:页的编号、其上一页、下一页是谁等)。

文件头的大小为 38 字节。构成如下:

重点讲解上述标为黄色的属性。

**FIL_PAGE_OFFSET(4 字节):**页号、页码,好比人的身份证号一样,InnoDB 可以通过页号 唯一确定一个页。

**FIL_PAGE_TYPE(2 字节):**代表当前页的类型,页的类型有以下分类(重点是 Undo 日志页 系统页)。

**FIL_PAGE_PREV(4 字节)和 FIL_PAGE_NEXT(4 字节):**InnoDB 是以页为单位存储数据的,数据分散到多个不连续的页中需要把这些页关联起来,FIL_PAGE_PREVFIL_PAGE_NEXT就是记录上一页和下一页的页号。这也就是上一篇 索引的数据结构中所说的,页与页之间是通过双向链表关联起来的。

从而保证:页与页之间在物理上不连续,但在逻辑上连续

**FIL_PAGE_SPACE_OR_CHKSUM(4 字节):**代表当前页面的校验和(checksum)。

什么是校验和?

简单理解,就是一个很长的字符串,通过某种特定的算法将整个字符串计算出一个比较短的值,这个值就是这个字符串的 校验和。最常见的是 Hash 算法。

校验和有什么作用?

eg:如果要比较两个很长的字符串,直接进行比较,会比较慢,通过比较两个字符串的校验和(生成校验和耗时可以忽略不计),校验和相同,则代表两个字符串相同,反之则不同。

重点: 文件头和文件尾中都有这个属性:FIL_PAGE_SPACE_OR_CHKSUM

在页面中的作用:

InnoDB 存储引擎以页为单位进行 I/O 操作,如果某个页从磁盘加载到内存中被修改了,那么 在修改后的某个时间段内需要将数据同步到磁盘中,假如在同步到一半的时候断电了,会造成该页数据传输的不完整。

为了验证一个页是否完整(也就是在同步的时候有没有发生只同步到一半的情况),这个时候可以通过 文件头的校验和文件尾的校验和进行比对,如果两个值不同则说明页的传输有问题,需要重新进行传输或回滚,否则任务页的传输已经完成。

再具体一点的过程:

每当一个页面在内存中被修改了,在同步之前要把他的校验和算出来,因为 File Header 在页面的最前面,所以最下被同步到磁盘中,当完全写完时,校验和也会被同步到 File Trailer 中,如果完全同步成功,文件头部和尾部的校验和应该相同,如果同步的过程中发生了异常,则文件头的校验和代表已经修改过的页,文件尾的校验和代表原来的页,这就说明同步数据出现了差错,需要进行 数据重试 或者 回滚 等操作。这里的校验方式就是采用的 Hash 算法。

**FIL_PAGE_LSN(8 字节):**页面最后被修改时对应的日志序列位置(Log Sequence Number,简称:LSN)。

File Trailer(文件尾)

**前 4 个字节:**代表校验和,和文件头中的校验和相对应。

**后 4 个字节:**代表页面最后被修改时的日志序列位置(LSN),这个部分也是为了校验页的完整性,如果文件头和文件尾的 LSN 值不同,也说明在同步的过程中出错了。

第 2 部分:空闲空间、用户记录、最大最小记录

这部分主要是存储记录,所以 用户记录最大最小记录占据了主要空间。

Free Space(空闲空间)

存储的记录会按照指定的 行格式存储到 User Record部分。在最开始生成页的时候,并没有 User Record部分。每次插入一条数据的时候,都会从 Free Space(空闲空间)中申请一条记录大小的空间划分为 User Record部分,当 Free Space 的空间被申请完之后,也就代表 Free Space 全部被 User Record 替代了,这个时候如果要在插入新的数据,就要申请新的数据页了。

User Record(用户记录)

User Record 中的记录按照 指定的行格式相互之间形成 单链表

这里的每一行的用户记录对应下文中的 InnoDB 一行记录是如何存储的?这里先不描述,下文逐步讲解。

Infimum+Supremum(最大和最小记录)

对于一条完整的记录来说,比较记录的大小是通过 主键值来判断的,记录会按照主键值大小依次递增排列存储。

InnoDB 规定的最小记录和最大记录构造很简单,都是由 5 字节大小的记录头信息和 8 字节大小的固定部分组成,如下图所示:

这两条记录不是我们自定义的,是 InnoDB 在生成页的时候默认创建的,所以它们来并不存放在 User Records 部分,而是单独存放在 Infimum + Supremum部分,如图所示:

这里有个特殊属性 heap_no,当前页的记录序列号,我们插入数据的记录 heap_no值都是从 2开始,就是因为会默认创建两条最大记录和最小记录,分别占了 01

第 3 部分:页目录、页面头部

Page Directory(页目录)

假设一条查询 SQL

select * from page_demo where c1 = 3;

方式 1:顺序查找

从 Infimum 记录(最小记录)开始,沿着链表一直往后找,数据量非常大的时候,性能非常差。

方式 2:使用页目录,二分法查找

  1. 将所有的记录分成若干个组,这些记录中包含最小记录和最大记录,但不包括 被标记为删除 的记录。
  2. 第 1 组只有一条记录,最小记录所在的组。最后一组 也就是最大记录所在的分组,会有 1-8条记录。其他分组,数量在 4-8条记录。【这样做的好处是除了第 1 组外,其余组的记录数会 尽量平分
  3. 每个组中的最后一条记录的头信息中会存储该组中一共有多少条记录,作为 n_owned字段的值。
  4. 页面录 用来存储 最后一条记录的地址偏移量,这些地址偏移量会按照顺序存储起来,每组的地址偏移量也被称为 槽(Slot),每个槽相当于指针指向了不同组的最后一条记录

每个页中的记录分组之后如下图所示:

根据上文举的例子,库中现在有 4 条真是用户记录,还有两条隐含的最大和最小记录,分组之后如下图所示:

上图的槽位:

  • 槽 0:指向的是最小记录的地址偏移量
  • 槽 1:指向的是最大记录的地址偏移量

再换个角度,单纯从逻辑上看一下这些记录和页目录的关系:

页目录中分组的个数是如何确定的?

这个问题也就是上述分组中,为什么第 1 组中最小记录的n_owned1,第 2 组中最大记录的n_owned5的问题?

InnoDB 规定:第 1 组只有一条记录,最小记录所在的组。最后一组 也就是最大记录所在的分组,会有 1-8条记录。其他分组,数量在 4-8条记录。【这样做的好处是除了第 1 组外,其余组的记录数会 尽量平分

分组的步骤如下所示:

  • 页初始化情况下只有两条记录:最小记录和最大记录,分别属于两个组。
  • 之后每插入一条记录,都会从页目录(槽位数组)中找到比当前记录的主键值大并且差值最小的槽(组),然后把该槽对应记录的 n_owned的值 加 1,表示本组内又添加了一条记录,直到该组的记录数等于 8个。
  • 在一个组中的记录数等于 8个后再插入一条记录时,会将该组中的记录拆分为两个组,一个组 4条记录,另一个组 5条记录。这个过程会在页目录中新增一个槽位(新组)来记录这个新增分组中最大的那条记录的 地址偏移量
页目录结构下如何快速查找记录?

为了模拟大数据量下如何查找记录的过程,新增了 12 条数据:

insert into page_demo values
(5, 500, 'zhou'),
(6, 600, 'chen'),
(7, 700, 'deng'),
(8, 800, 'yang'),
(9, 900, 'wang'),
(10, 1000, 'zhao'),
(11, 1100, 'qian'),
(12, 1200, 'feng'),
(13, 1300, 'tang'),
(14, 1400, 'ding'),
(15, 1500, 'jing'),
(16, 1600, 'quan');

根据 InnoDB 规定,分为以下几组槽位:

这里为了方便展示,只保留了 16 条记录的头信息中的 n_ownednext_record属性,省略了各个记录之间的箭头。

上图中左边的槽位数组就可以采用二分法查找,查询过程如下:

  • 找到对应的槽位之后,如果要查找的记录的主键值恰巧为 8,对应上述槽 2 中的最大记录,直接返回
  • 如果要查找的记录的主键值为 6,从上图中可以看出也是在槽 2 中,但是我们之前说过,记录与记录之间是通过单链表的形式链接的,所以直接定位到槽 2 是无法往前扫描主键值小的记录
  • 这个时候我们可以找到槽 1 对应的最大记录 主键值为 4,根据 next_record往后查找两个位置即可找到主键值为 6的记录

小结:

在一个数据页中查找指定主键值记录的过程分为两步:

  1. 通过二分法确定 要查找记录所在的槽位上一个槽位,并找到该槽所在的分组中主键值最大的记录
  2. 通过当前最大记录的 next_record属性往后遍历,也就可以遍历到 要查找的真实记录 所在的分组中的每一个记录

Page Header(页面头部)

为了能得到一个数据页中存储的记录的状态信息,

  • 比如本页中已经存储了多少条记录?
  • 第一条记录的地址是什么?
  • 页目录中存储了多少个槽等

特意在页中定义了一个叫 Page Header 的部分,这个部分占用了固定的 56 个字节,专门存储当前页的各种状态信息。

有以下属性:

PAGE_DIRECTION

假如新插入的一条记录的主键值比上一条插入记录的主键值大,我们称这条记录的插入方向是向右,反之则向左。这个标识用来表示最后一条记录插入方向的状态 PAGE_DIRECTION

PAGE_N_DIRECTION

假设连续 N 次插入的记录的方向都是一致的,InnoDB 会把沿着同一个方向插入记录的条数记下来,这个条数就用 PAGE_N_DIRECTION这个状态表示。当然如果最后一条记录的插入方向改变的话,这个状态的值就会被清零重新统计。

第 4 部分:从数据页的角度看 B+Tree 如何查询

B+Tree 数据是如何记性记录检索的?

通过 B+Tree 的索引查询记录,首先通过根节点开始逐层检索,直到找到记录所在的叶子节点,然后将整个数据页从磁盘中加载到内存中,页目录中的槽(slot)可以通过 二分查找的方式定位到记录所在的槽(分组),通过 链表遍历的方式查找到记录。

普通索引和唯一索引在查询效率上有什么不同?

唯一索引就是在普通索引上增加了约束,也就是关键字唯一,找到关键字之后就停止检索。

而普通索引存在关键字重复的情况,我们知道 InnoDB 存储引擎索引的一个数据页的大小为 16KB,每次 I/O 操作会将记录所在的整个数据页加载到内存中,因为关键字存在重复的情况,所以查找到关键字的记录之后,相比 唯一索引还会继续往后再多判断几次记录是否符合关键字查询条件,但是在 CPU 中,多的几次判断消耗的时间可以忽略不计,整体上来来说,普通索引和唯一索引在查询效率上没有多大差别。

本文内容总结借鉴于康师傅的 MySQL 视频课:https://www.bilibili.com/video/BV1iq4y1u7vj


在这里插入图片描述

一起学编程,让生活更随和!

如果你觉得是个同道中人,欢迎关注博主gzh:【随和的皮蛋桑】。

专注于Java基础、进阶、面试以及计算机基础知识分享🐳。偶尔认知思考、日常水文🐌。

在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Open3D 最小二乘拟合平面——拉格朗日乘子法

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接Open3D 最小二乘拟合平面——拉格朗日乘子法。爬虫自重。 一、算法原理 设拟合出的平面方程为: a x + b y +

宣传照(私密)勿转发

精美的海报通常都是由UI进行精心设计的,现在有100 件商品需要进行宣传推广,如果每个商品都出一张图显然是不合理的,且商品信息各异。因此需要通过代码的形式生成海报。对此,我也对我宣传一波,企图实现我一夜暴富的伟大…

Nice Water Shader

非常好的水着色器! 标准RP上的新程序泡沫!!(URP即将推出) URP支持!! 有3个版本: -台式机 -移动设备 -桌面拼接 有灯光支持!! 使用 CUSTOM SHADER INSPECTOR(自定义着色器检查器) 个性化事物的能力,如: 镶嵌图案 3种不同颜色,形成渐变深度 色彩位置优势 菲涅耳颜色和…

[讲座] - 闲聊工业设计

1,工业设计相关的学科分类 2,工业设计的职业发展路线 3,工业设计师的成名人物 4,设计了可口可乐的Loewy 可口可乐的瓶子,无论白天晚上还是瓶子被打碎,都能认出这个是可口可乐的瓶子。 草图参照了可可豆&am…

GZ075 云计算应用赛题第4套

2023年全国职业院校技能大赛(高职组) “云计算应用”赛项赛卷4 某企业根据自身业务需求,实施数字化转型,规划和建设数字化平台,平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”,拟采用开源OpenSt…

Oracle笔记-查看表已使用空间最大空间

目前以Oracle18c为例,主要是查这个表USER_SEGMENTS。 在 Oracle 18c 数据库中,USER_SEGMENTS 是一个系统表,用于存储当前用户(当前会话)拥有的所有段的信息。段是 Oracle 中分配存储空间的逻辑单位,用于存…

数据结构和算法-数据结构的基本概念和三要素和数据类型和抽象数据类型

文章目录 总览数据结构的基本概念总览数据早期和现代的计算机处理的数据数据元素-描述一个个体数据对象-一类数据元素什么是数据结构小结 数据结构的三要素总览逻辑结构-集合结构逻辑结构-线性结构逻辑结构-树形结构逻辑结构-图形结构逻辑结构-小结数据的运算物理结构&#xff…

JAVA对象、List、Map和JSON之间的相互转换

JAVA对象、List、Map和JSON之间的相互转换 1.Java中对象和json互转2.Java中list和json互转3.Java中map和json互转 1.Java中对象和json互转 Object obj new Object(); String objJson JSONObject.toJSONString(obj);//java对象转json Object newObj JSONObject.parseObject(…

一类医疗器械需要做EMC和安规吗?

摘要: 在医疗器械领域,EMC(电磁兼容性)和安规(安全规格)测试是非常重要的。医疗器械需要符合电磁兼容性标准,以确保其在电磁环境下能够正常运行而不会受到外部电磁干扰的影响,也不会干扰其他设备…

IOS - 手机安装包 ipa 常见几种方式

安装 ipa 包的方法有很多中,可以通过不同的软件安装,本文只列出了常用的几种,做个简单的归纳整理 1、iTunes 安装 数据线连接手机之后,会自动连接iTunes,(第一次连接的时候会提示是否信任此电脑&#xff0…

小红书、抖音、视频号下载工具:随心管理个人作品集 | 开源日报 No.134

karanpratapsingh/system-design Stars: 20.6k License: NOASSERTION 这个项目是关于系统设计的。它提供了有关系统设计的课程内容,包括 IP、OSI 模型、TCP 和 UDP 等主题。该项目的核心优势和特点如下: 提供全面而高效的系统架构定义。从基础设施到数…

k8s的声明式资源管理

在k8s当中支持两种声明资源的方式: 1、 yaml格式:主要用于和管理资源对象 2、 json格式:主要用于在API接口之间进行消息传递 声明式管理方法(yaml)文件 1、 适合对资源的修改操作 2、 声明式管理依赖于yaml文件,所有的内容都…

小白入门基础 - tomcat

一:前言 Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为&#x…

【解决】Unity 设置跨设备分辨率表现

开发平台:Unity 2018版本以上 开发语言:CSharp 编程平台:Visual Studio 2022   问题描述 使用 UnityEngine.dll 中关于设置分辨率的方法时,无法满足应用以设定分辨率进行屏幕显示问题。因而造成画面不同程度的拉伸情况。而这种情…

[概率论]四小时不挂猴博士

贝叶斯公式是什么 贝叶斯公式是概率论中的一个重要定理,用于计算在已知一些先验信息的情况下,更新对事件发生概率的估计。贝叶斯公式的表达式如下: P(A|B) P(B|A) * P(A) / P(B) 其中,P(A|B)表示在事件B发生的条件下事件A发生的概…

【Emgu.CV教程】第21篇 、色彩处理之ConvertTo()函数改变图像的亮度和对比度

先画重点: 亮度是指图像的整体明亮程度。增加亮度会使图像整体变得更加明亮,而减少亮度则会使图像变暗。对比度是指图像中不同区域之间亮度差异的程度。它衡量了图像中最亮和最暗区域之间的差异。对比度高的图像明暗差异大,而对比度低就是明…

2024.1.2 安装JDK和Eclipse,并配置java编译环境

2024.1.2 安装JDK和Eclipse,并配置java编译环境 一直对java一知半解,利用春节前一个月时间补补课。 一、安装jdk 首先在oracle官网上下载jdk,这里选jdk17,选择第二项直接安装,第一项是压缩文件,带有一些…

二分图的最大权匹配

二分图的最大权匹配 二分图的最大匹配 匈牙利算法 思路&#xff1a;将点分为两类&#xff0c;左边的点和右边的点。每次尝试给左边的点找一个右边的点与之匹配&#xff0c; for (int i 1; i < n; i) {Arrays.fill(st, false);//为什么要每次都要重置stif (find(i)) res…

企业CIO如何面对数字化转型

随着互联网新技术的不断发展&#xff0c;必将导致商业模式的改变&#xff0c;企业信息化的内涵也将发生改变。IT在企业的定位更可能会上升到合作伙伴型与引领型这些较高的层面&#xff0c;IT架构模式、系统建设模式、IT部门结构等都将发生质变。而数字化时代必定属于CIO的时代&…

浅谈余压监控系统在某高层住宅的应用方案

【摘要】&#xff1a; 本文介绍了余压监控系统的基本架构和功能&#xff0c;结合某高层住宅建设实例分析了高层民用建筑中设置此系统的优点与必要性&#xff0c;总结了余压监控系统的功能用于高层建筑物中楼梯间和前室、前室和走道之间的余压的监控与调节&#xff0c;使监控区域…