大纲

1.表空间文件结构

(1)表空间Tablesapce

(2)段Segment

(3)区Extend

(4)页Page

(5)行Row

2.Page结构

(1)页结构各部分说明

(2)页结构整体划分

3.行记录格式

(1)行格式分类

(2)COMPACT行记录格式

(3)Compact中的行溢出机制

(4)其他行格式记录

1.表空间文件结构

(1)表空间Tablesapce

(2)段Segment

(3)区Extend

(4)页Page

(5)行Row

InnoDB表空间文件结构从逻辑上可以分为:

Tablespace(表空间)->Segment(段)->

Extent(区)->Page(页)->Row(行)

一个表空间会包含多个段,一个段会包含多个区(256个区就是一个组);一个区又会包含64个页,一个页里面又会包含一行一行的记录Row。

(1)表空间Tablesapce

一.表空间是什么

表空间能够看作是InnoDB存储引擎逻辑结构的最高层。表空间用于存储多个ibd数据文件,用于存储表的记录和索引。一个表空间文件可以包含多个段:叶子节点段、非叶子节点段、回滚段。

二.表空间类型

系统表空间、独占表空间、通用表空间、 临时表空间、Undo表空间。

(2)段Segment

一.段是什么

段是用来管理空间的申请以及将同类的区和页用链表管理起来。段是个逻辑概念,本质上是由若干个零散页面和若干个完整的区组成。段是为了保持叶子节点在磁盘上的连续,可以实现更好的顺序IO操作。

一个B+树索引被划分为两个段:一个叶子节点段和一个非叶子节点段。这样叶子节点就可以尽可能地存放在一起,非叶子节点也可以尽可能地存放在一起。

二.段的类型

常见的段有数据段、索引段、回滚段等。其中索引段就是非叶子节点部分,而数据段就是叶子节点部分,回滚段用于数据的回滚和多版本控制。

三.为什么引入段

原因一:

使用B+树执行查询时只是扫描叶子节点记录,如果不区分叶子节点和非叶子节点,通通把节点代表的页面放到申请的区中,那么扫描效果就大打折扣,而段可以让叶子节点的数据页尽可能连续和差距不那么大。所以InnoDB对B+树的叶子节点和非叶子节点进行区别对待,叶子节点和非叶子节点各有自己独有的区。而存放叶子节点的区的集合就算是一个段,存放非叶子节点的区的集合也算是一个段。即一个索引会生成两个段:一个叶子节点段和一个非叶子节点段。

原因二:

以完整的区为单位分配给某个段时,对于数据量较小的表来说太浪费存储空间。因为当段以区为单位申请存储空间时,由于一个区默认占用1MB存储空间以及一个聚簇索引会生成两个段,所以默认情况下只存放了几条记录的小表也需要2MB的存储空间,这就有点浪费了。

原因三:

出现上述问题的根源是:区中的所有页面都是为了存储同一个段的数据而存在,即使区的页面用不完也不能作他用。于是InnoDB便有了碎片区。在一个碎片区中,并非所有页都是为了存储同一个段的数据而存在,碎片区的页可以用于不同的目的的。比如有些页属于段A、有些页属于段B、有些页甚至不属于任何段。碎片区直属于表空间,不属于任何段。

原因四:

为某个段分配存储空间的策略:刚开始向表中插入数据时,段是从某个碎片区中以单个页面为单位来分配存储空间的。当某个段已经占用了32个碎片区页面后,就会以完整的区为单位来分配存储空间,原先占用的碎片区页面并不会被复制到新申请的完整的区中。所以说,段是一些零散的页面以及一些完整的区的集合。

(3)区Extend

一.区是什么

区由连续页组成的空间,一个区的大小是1M,一个区有64个连续的页。为了保证区中页的连续性,扩展时InnoDB一次从磁盘申请4~5个区。无论是系统表空间还是独立表空间,都可看成是由若干个连续的区组成。当一个段使用了32个碎片页后才是以区来分配,每256个区被分成一组。

二.为什么引入区

原因一:

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

原因二:

使用B+树来减少记录的扫描行数的过程是:通过一些搜索条件,到B+树的叶子节点中定位到第一条符合该条件的记录,然后沿着由记录组成的单向链表以及由数据页组成的双向链表,一直向后进行扫描。全表扫描就是定位到第一个叶子节点的第一条记录。

原因三:

如果双向链表中相邻的两个页的物理位置不连续,对于传统的机械硬盘来说,需要重新定位磁头位置,也就是会产生随机IO,影响性能。所以应尽量让页面链表中相邻的页的物理位置也相邻,以便扫描叶子节点的大量记录时可以使用顺序IO。

原因四:

为了尽量消除随机IO才引入了区的概念,一个区就是物理位置上连续的64个页,区中页面的页号都是连续的。当表中的数据量很大时,为某个索引分配空间时就不再按页为单位来分配了,而是按照区为单位进行分配。甚至当表中的数据非常非常多的时候,可以一次性分配多个连续的区,以消除更多的随机IO,但会造成一点空间的浪费。

(4)页Page

一.页是什么

区是由连续的页(Page)组成的空间,一个页的存储大小为16K,页用于存储多个Row行记录。

二.页的类型

页有很多种类型,如数据页、Undo页、系统页、事务数据页、大的BLOB对象页。

(5)行Row

InnoDB的数据是按行的方式进行存放的,每个页存放的行记录最多允许存放16K / 2 - 200行的记录,即每个页最多存放7992行记录。每行记录根据不同的行格式、不同的数据类型,会有不同的存储方式。

行包含的内容:记录的字段值、事务ID、回滚指针、字段指针等信息。

2.Page结构

(1)页结构各部分说明

(2)页结构整体划分

Page是InnoDB存储的最基本构件,也是InnoDB磁盘管理的最小单位,与数据库相关的所有内容都存储在这种Page结构里。

Page分为几种类型,常见的页类型有:数据页(B+Tree Node)、Undo页(Undo Log Page)、系统页(System Page)、事务数据页(Transaction System Page)等。

(1)页结构各部分说明

一.File Header字段用于记录Page的头信息

其中比较重要的是FIL_PAGE_PREV和FIL_PAGE_NEXT字段。通过这两个字段,就可以找到该页的上一页和下一页。实际上所有页通过两个字段可以形成一条双向链表。

二.Page Header字段用于记录Page的状态信息

三.Infimum和Supremum是最小和最大行记录

Infimum(下确界)记录比该页中任何主键值都要小的值,Supremum(上确界)记录比该页中任何主键值都要大的值,这两个伪记录构成了页中记录的边界。

四.User Records存放的是实际的数据行记录

五.Free Space中存放的是空闲空间

被删除的行记录会成为空闲空间。

六.Page Directory记录与二叉查找相关的信息

七.File Trailer存储检测数据完整性的数据

(2)页结构整体划分

页结构整体上可以分为三大部分,分别为:通用部分(文件头、文件尾)、数据记录部分、页目录部分。

一.通用部分(File Header&File Trailer)

通用部分主要指文件头和文件尾,将页的内容进行封装。通过文件头和文件尾校验的CheckSum方式可以确保页的传输是完整的,这时候就可以确认是否发生页断裂也就是页是否写失效了。

其中比较重要的是在文件头中的FIL_PAGE_PREV和FIL_PAGE_NEXT字段,通过这两个字段,可以找到该页的上一页和下一页,因此所有页可以形成一条双向链表。

二.数据记录部分(User Records&Free Space)

由于页的主要作用是存储记录,所以"最小和最大记录"和"用户记录"部分占了页结构的主要空间。另外空闲空间是个灵活的部分,当有新的记录插入时,会从空闲空间中进行分配用于存储新记录。

三.页目录部分(Page Directory)

数据页中的行记录会按照主键值由小到大顺序串联成一个单链表,单链表的链表头为最小记录,链表尾为最大记录。数据页目录中会顺序存储每一条行记录的地址,通过对数据页目录使用二分法,就能快速定位到查找的行记录。

3.行记录格式

(1)行格式分类

(2)COMPACT行记录格式

(3)Compact中的行溢出机制

(4)其他行格式记录

(1)行格式分类

表的行格式决定了它的行是如何物理存储的,这反过来又会影响查询和DML操作的性能。

如果在单个Page页中容纳更多行,那么查询和索引查找就能更快地工作,并且缓冲池中所需的内存会更少,写入更新时所需的IO也会更少。

InnoDB存储引擎支持四种行格式:Redundant、Compact、Dynamic和Compressed。

下面查询MySQL使用的行格式,MySQL5.7后默认是dynamic。

mysql> show variables like 'innodb_default_row_format';
+---------------------------+---------+
| Variable_name | Value |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+

下面是指定行格式的语法:

CREATE TABLE <table_name(column_name)> ROW_FORMAT=行格式名称
ALTER TABLE <table_name> ROW_FORMAT=行格式名称

(2)COMPACT行记录格式

Compact设计目标是高效地存储数据,一个页中存放的行数据越多,其性能就越高。Compact行记录由两部分组成:记录的额外信息和记录的真实数据。

一.记录额外信息部分

服务器为了描述一条记录而添加了一些额外信息(元数据信息),这些额外信息分为3类,分别是:变长字段长度列表、NULL值列表和记录头信息。

第一类:变长字段长度列表

MySQL支持一些变长的数据类型,比如VARCHAR(M)、VARBINARY(M)、各种TEXT类型,各种BLOB类型。这些变长的数据类型占用的存储空间分两部分:真正的数据内容和占用的字节数。

变长字段的长度是不固定的,所以在存储数据时要把这些数据占用的字节数也存起来。读取数据时才能根据这个长度列表去读取对应长度的数据。

在Compact行格式中:会把所有变长类型的列的长度都存放在记录的开头部位形成一个列表,按照列的顺序逆序存放,这个列表就是变长字段长度列表。

第二类:NULL值列表

表中的某些列可能会存储NULL值,如果把这些NULL值都放到记录的真实数据中会比较浪费空间,所以Compact行格式把这些值为NULL的列存储到NULL值列表中。如果表中所有列都不允许为 NULL,就不存在NULL值列表。

第三类:记录头信息

记录头信息是由固定的5个字节组成,5个字节也就是40个二进制位,不同的位代表不同的意思。

delete_mask:这个属性标记着当前记录是否被删除,占用1个二进制位。值为0时代表记录并没有被删除,值为1时代表记录被删除掉。

min_rec_mask:标记该记录是否是B+树的每层非叶子节点中的最小记录。

n_owned:代表每个分组里,所拥有的记录的数量,一般是分组里主键最大值才有的。

heap_no:在数据页的User Records中插入的记录是一条条紧凑排列的,这种紧凑排列的结构又被称为堆。为了便于管理这个堆,把记录在堆中的相对位置给定一个编号heap_no,所以heap_no这个属性表示当前记录在本页中的位置。

record_type:这个属性表示当前记录的类型,一共有4种类型的记录。0表示普通用户记录、1表示B+树非叶节点记录、2表示最小记录、3表示最大记录。

next_record :表示从当前记录的真实数据到下一条记录的真实数据的地址偏移量,可以理解为指向下一条记录地址的指针。值为正数说明下一条记录在当前记录的后面,值为负数说明下一条记录在当前记录的前面。

二.记录真实数据部分

除了记录真实数据以外,MySQL还会为每条行记录添加一些列。这些列被称为隐藏列,具体的列如下:

列说明如下:

生成隐藏主键列的步骤:

步骤一:

服务器会在内存中维护一个全局变量,每当向某个包含隐藏的row_id列的表中插入一条记录时,就会把该变量的值当作新记录的row_id列的值,并且把该变量自增1。

步骤二:

每当这个变量的值为256的倍数时,就会将该变量的值,刷新到系统表空间的页号为7的页面中一个Max Row ID的属性中。

步骤三:

系统启动时会将页中的Max Row ID属性加载到内存中,并将该值加上256后赋值给全局变量,因为在上次关机时该全局变量的值可能大于页中Max Row ID属性值。

(3)Compact中的行溢出机制

一.什么是行溢出

MySQL中是以页为基本单位进行磁盘与内存之间的数据交互的。一个页的大小是16K = 16384字节。一个varchar(m)类型列最多可以存储65532个字节,一些大的数据类型如TEXT可以存储更多。如果一个表存在这样的大字段,那么一个页就无法存储一条完整的记录。这时就会发生行溢出,多出的数据就会存储在另外的溢出页中。

总结:如果某些字段信息过长,无法存储在B树节点中。这时候会被单独分配空间,此时被称为溢出页,该字段被称为页外列。

二.Compact中的行溢出机制

InnoDB规定一页至少存储两条记录(B+树特点),如果页中只能存放下一条记录,InnoDB会自动将行数据存放到溢出页中。当发生行溢出时,数据页只保存前768字节的前缀数据,接着是20个字节的偏移量,指向行溢出页。

(4)其他行格式记录

一.DYNAMIC和COMPRESSED行记录格式

DYNAMIC和COMPRESSED新格式引入的功能有:数据压缩、增强型长列数据的页外存储和大索引前缀。

Compressed和Dynamic行记录格式与Compact行记录格式是类似的。区别是在处理行溢出时:数据页不会存储真实数据的前768字节(完全溢出),而只存储20个字节的指针来指向溢出页。

Compressed与Dynamic相比:Compressed存储的行数据会以zlib的算法进行压缩以节省空间,因此对于BLOB、TEXT、VARCHAR这类大长度类型的数据能有效存储。MySQL5.7默认的行记录格式是Dynamic。

二.Redundant

Redundant是MySQL 5.0版本前InnoDB的行记录存储方式。Redundant行记录的格式是:首部是一个字段长度偏移列表,同样是按照列的顺序逆序放置的,该条记录中所有列的长度信息都按照逆序存储到字段长度偏移列表,这些列当然包括隐藏列、NULL值列等。

MySQL底层概述—4.InnoDB数据文件的更多相关文章

  1. MySQL架构原理之存储引擎InnoDB数据文件

    MySQL架构原理之体系架构 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中简单介绍了MySQL的系统文件层,其中包含了数据文件.那么InnoDB的数据文件是如何分类并存储的呢? 一. ...

  2. 营销MM让我讲MySQL日志顺序读写及数据文件随机读写原理

    摘要:你知道吗,MySQL在实际工作时候的两种数据读写机制? 本文分享自华为云社区<MySQL日志顺序读写及数据文件随机读写原理>,作者:JavaEdge . MySQL在实际工作时候的两 ...

  3. mysql数据库存储路径更改 数据文件位置

    使用了VPS一段时间之后发现磁盘空间快满了.本人的VPS在购买的时候买了500gb的磁盘,提供商赠送了20GB的高性能系统磁盘.这样系统就有两个磁盘空间了.在初次安装mysql 的时候将数据库目录安装 ...

  4. 电商网站垮IDC数据备份,MySql主从同步,图片及其它数据文件的同步

    原文网址:http://www.bzfshop.net/article/180.html 对一个电子商务网站而言,最宝贵的资源就是数据.服务器是很廉价的东西,即使烧了好几个也问题不大,但是用户数据如果 ...

  5. MySQL的奇怪的删表数据文件而表照样能打开

    MySQL的奇怪的删表数据文件而表照样能打开 author:headsen  chen      2017-11-02   17:57:17 现象:删除一个正在运行的mysql数据库的表的数据文件:* ...

  6. [MySQL Reference Manual]14 InnoDB存储引擎

    14 InnoDB存储引擎 14 InnoDB存储引擎 14.1 InnoDB说明 14.1.1 InnoDB作为默认存储引擎 14.1.1.1 存储引擎的趋势 14.1.1.2 InnoDB变成默认 ...

  7. MySQL底层索引剖析

    1:Mysql索引是什么 mysql索引: 是一种帮助mysql高效的获取数据的数据结构,这些数据结构以某种方式引用数据,这种结构就是索引.可简单理解为排好序的快速查找数据结构.如果要查“mysql” ...

  8. 洞悉MySQL底层架构:游走在缓冲与磁盘之间

    提起MySQL,其实网上已经有一大把教程了,为什么我还要写这篇文章呢,大概是因为网上很多网站都是比较零散,而且描述不够直观,不能系统对MySQL相关知识有一个系统的学习,导致不能形成知识体系.为此我撰 ...

  9. mysql之show engine innodb status解读

    注:以下内容为根据<高性能mysql第三版>和<mysql技术内幕innodb存储引擎>的innodb status部分的个人理解,如果有错误,还望指正!!   innodb存 ...

  10. 【MySQl】MyISAM和InnoDB索引对比

    部分内容转自:http://www.2cto.com/database/201211/172380.html 比较好的文章:http://www.cnblogs.com/hustcat/archive ...

随机推荐

  1. JavaScript – 类型转换

    介绍 JS 是弱类型语言, 在编程时, 有许多自动类型转换的技巧, 虽然大家都不太鼓励, 尤其是用了 TypeScript 之后, 但无可否认自动转换很方便, 看上去也很干净. 所以这篇还是要介绍一些 ...

  2. HiveServer2 文件描述符泄漏

    现象 用户反馈 hs2 打开的文件描述符的数量一直在涨,但是当前 hs2 的连接只有个位数. 排查过程 首先找到 hs2 进程持有了哪些文件描述符,通过 lsof 命令 lsof -p $pid ,看 ...

  3. 三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询...)

    三,MyBatis-Plus 的各种查询的"超详细说明",比如(等值查询,范围查询,模糊查询...) @ 目录 三,MyBatis-Plus 的各种查询的"超详细说明&q ...

  4. 解决 Vue 项目打包上线后客户端缓存的问题

    由于重新打包后会导致对应的 js 和 css 文件 hash 值发生变化,客户端不刷新的话就会存在之前的文件找不到,导致报错的问题. 通过 build.sh 定义打包命令 #!/usr/bin/env ...

  5. Laravel视图共享数据

    Laravel视图共享数据 最近在用lavavel过程中想实现公共头部尾部需要的配置数据在所有的页面中都可以使用,便查看了官方文档,在此做一个总结: 一. 修改 ComposerServiceProv ...

  6. 比赛题解 更新ING

    CF Codeforces Round #750 (Div. 2) (水题.组合数学.双指针+搜索.构造.dp.dp) Codeforces Round #747 (Div. 2) (水题.水题.埃筛 ...

  7. Octave 安装教程

    Octave 用心写著. Octave为GNU项目下的开源软件.同时它也是一种语言,专注于解决线性计算问题.因为对于矩阵计算的优化,使得其速度远高于循环计算.语法兼容Linux shell. Octa ...

  8. react hooks 渲染性能

    目录 目录 重复渲染 React.memo() 例子 React.useMemo 例子 React.useMemo 也可以绑定 jsx和tsx对象 React.useCallback() 例子 重复渲 ...

  9. 使用wxpython开发跨平台桌面应用,实现程序托盘图标和界面最小化及恢复处理

    在前面随笔<基于wxpython的跨平台桌面应用系统开发>介绍了一些关于wxpython开发跨平台桌面应用的总体效果,开发桌面应用,会有很多界面细节需要逐一处理,本篇随笔继续深入该主题,对 ...

  10. .Net Core NPOI 导出多级表头

      想要导出这样的表格 数据准备格式 附上源码 1 using NPOI.HSSF.UserModel; 2 using NPOI.SS.UserModel; 3 using NPOI.SS.Util ...