文章目录
- [1. InnoDB存储引擎](#1. InnoDB存储引擎)
-
- [1.1 InnoDB存储引擎的前世今生](#1.1 InnoDB存储引擎的前世今生)
- [1.2 MySQL为什么默认使用InnoDB存储引擎?](#1.2 MySQL为什么默认使用InnoDB存储引擎?)
- [1.3 一些问题](#1.3 一些问题)
- [1.4 InnoDB存储引擎的架构长啥样?](#1.4 InnoDB存储引擎的架构长啥样?)
-
- [1.4.1 为什么要设计成内存结构和磁盘结构两个部分?](#1.4.1 为什么要设计成内存结构和磁盘结构两个部分?)
- [1.4.2 内存结构和磁盘结构中每个部分的作用是什么?](#1.4.2 内存结构和磁盘结构中每个部分的作用是什么?)
- [1.5 使用InnoDB存储引擎创建的表对应的数据文件在哪里?](#1.5 使用InnoDB存储引擎创建的表对应的数据文件在哪里?)
-
- [1.5.1 新问题](#1.5.1 新问题)
- [2. MySQL存储结构](#2. MySQL存储结构)
-
- [2.1 什么是表空间文件?](#2.1 什么是表空间文件?)
-
- [2.1.1 表空间与表空间文件的关系是什么?](#2.1.1 表空间与表空间文件的关系是什么?)
- [2.2 用户数据在表空间中是怎么存储的?](#2.2 用户数据在表空间中是怎么存储的?)
-
- [2.2.1 新问题](#2.2.1 新问题)
- [2.3 为什么要使用页这个数据管理单元?](#2.3 为什么要使用页这个数据管理单元?)
-
- [2.3.1 什么是局部性原理?](#2.3.1 什么是局部性原理?)
- [2.4 数据页有哪些基本特性是必须要掌握的? - 页](#2.4 数据页有哪些基本特性是必须要掌握的? - 页)
- [2.5 查询的数据超过一页的大小,怎么提高查询效率 ?区](#2.5 查询的数据超过一页的大小,怎么提高查询效率 ?区)
-
- [2.5.1 不同的页在磁盘中是不是连续的呢?](#2.5.1 不同的页在磁盘中是不是连续的呢?)
- [2.5.2 为什么不连续的地址会降低查询的效率?](#2.5.2 为什么不连续的地址会降低查询的效率?)
- [2.5.3 InnoDB如何保证页在磁盘中的连续性?](#2.5.3 InnoDB如何保证页在磁盘中的连续性?)
- [2.5.4 新问题](#2.5.4 新问题)
1. InnoDB存储引擎
1.1 InnoDB存储引擎的前世今生
InnoDB做为MySQL的默认存储引擎,其实并不是MySQL开发的,而是由Innobase Oy公司所开发,2006年五月时由甲骨文公司并购。这也是MySQL做为一个开源数据库的好处之一,第三方开发者可以根据自己的业务场景开发出高性能的存储引擎,像Innobase Oy公司开发的InnoDB,一旦被官方采纳,那么就可能通过被收购从而得到可观的收入,官方的产品也得到了有效的扩展,是一个双赢的结果。- 开源社区有很多,除了
MySQL之外,常见的还有Linux,Java,Android,开发都通过社区交流并贡献自己的技术,逐步完善各种应用场景下的技术支持,现在开发过程中使用的很多框架和中间件都得益与此。
1.2 MySQL为什么默认使用InnoDB存储引擎?
InnoDB在设计时考虑到了处理巨大数据量时的性能,InnoDB支持事务(transaction)、回滚(rollback)并且具有崩溃修复的能力(crash recovery capabilities),通过多版本并发控制(multiversionedconcurrency control)减少锁定,同时还支持外键约束(FOREIGN KEY constraints),通过缓冲池在主内存中缓存数据从而提高查询性能,也可以每个表使用各自的独立表空间存储数据并且文件大小只受限于操作系统,由于InnoDB存储引擎存储数据量大,性能高,可以有效的保证数据安全等优点,在MySQL5.5版本之后成为默认的存储引擎。
1.3 一些问题
InnoDB事务是什么?- 事务的回滚是什么?
InnoDB崩溃修复如何处理?- 多版本并发控制是什么?
- 锁分类都有哪些?
- 缓冲池的作用及工作原理?
- 独立表空间的作用及优点?
1.4 InnoDB存储引擎的架构长啥样?
InnoDB存储引擎架构链接:MySQL :: MySQL 8.0 Reference Manual :: 17.4 InnoDB Architecture下图是官方给出的
MySQL8.0架构图,可以看出其中InnoDB主要包括内存结构和磁盘结构:

内存结构中包括:
- 缓冲池(
Buffer Pool):内存中的主要工作区域,优化查询性能- 变更缓冲区(
Change Buffer):优化修改操作的性能- 日志缓冲区(
Log Buffer):记录需要同步到磁盘的日志,定时刷新到磁盘- 自适应哈希(
Adaptive Hash Index):进一步提升查询的性能磁盘结构中包括:(前
5个表空间保证保存的是真实的数据,最后两个保证数据安全)
- 系统表空间(
System Tablespace)- 独立表空间(
File-Per-Table Tablespaces)- 通用表空间(
General Tablespaces)- 临时表空间(
Temporary Tablespaces)- 撤销表空间(
Undo Tablespaces)- 重做日志(
Undo Log)- 双写缓冲区 (
Doublewrite Buffer)
这个问题在面试中可能会被问到,在回答时先说总体的架构分为内存和磁盘两部分,再分别说说内存和磁盘中都包括哪些组件就可以了
1.4.1 为什么要设计成内存结构和磁盘结构两个部分?
我们从
MySQL实现的角度来思考这个问题,数据库的作用就是保存数据,用户的真实数据最终都会保存在磁盘上,在查询数据的过程中,如果每次都从磁盘上读取会严重影响效率,为了提高数据的访问效率,InnoDB会把查询到的数据缓存到内存中,当再次查询时,如果目标数据已经存在于内存中,就可以从内存中直接读取,从而大幅提升效率。也就是说磁盘结构中的文件是用来保存数据实现数据持久化的,内存结构是用来缓存数据提升效率的。
1.4.2 内存结构和磁盘结构中每个部分的作用是什么?
下面的内容会逐个介绍内存结构和磁盘结构中各部分的作用和工作原理,这也是
InnoDB章节的主要内容。
1.5 使用InnoDB存储引擎创建的表对应的数据文件在哪里?
当使用
InnoDB存储引擎创建一个表时,默认会在数据目录对应的数据库子目录中生成相应的表空间文件,以.ibd为文件的后缀,用来存储数据和索引,如果每个表都对应一个表空间文件,称为独立表空间,在MySQL5.7及以后的版本中默认为每个表生成独立表空间,可以通过系统变量innodb_file_per_table[=ON|OFF]进行控制,如果关闭这个选项,则所有表的数据都在系统表空间中存储,独立表空间文件如下所示:

.ibd文件是使用InnoDB存储引擎创建的表对应的表空间文件。
1.5.1 新问题
打开与关闭成独立表空间选项的优缺点?
2. MySQL存储结构
2.1 什么是表空间文件?
表空间文件是用来存储表中数据的文件,表空间文件的大小由存储的数据多少决定,不同的表空间文件存储数据的种类也有所不同,在
MySQL中表空间分为五类,包括:
- 系统表空间
- 独立表空间
- 通用表空间
- 临时表空间
- 撤销表空间
这些在上面的
InnoDB架构图中都有体现。
2.1.1 表空间与表空间文件的关系是什么?
表空间可以理解为
MYSQL为了管理数据而设计的一种数据结构,主要描述的对结构的定义,表空间文件是对定义的具体实现,以文件的形式存在于磁盘上系统表空间、独立表空间、通用表空间、临时表空间和撤销表空间的作用?后面我们会详细介绍每种类型的表空间的作用。
2.2 用户数据在表空间中是怎么存储的?
用户的数据以数据行的方式存储在对应的表空间文件中,那么表空间中很多个数据行就需要进行管理,以便后续进行高效的查询;
为了方便管理,表空间由段 (
segment)、区组(group)、区 (extent)、页 (page) 、数据行组成,其中页是InnoDB磁盘管理的最小单位;可以这么理解,若干数据行组成了页,多个页组成了区,多区组成了区组,多个区组组成了段,多个段组成了表空间。
2.2.1 新问题
段 (
segment)、区组(group)、区 (extent)、页 (page) 、数据行是如何管理起来的?
2.3 为什么要使用页这个数据管理单元?
MySQL中的页是应用层的一个概念,是MySQL根据自身的应用场景,定义的一种数据结构。通常操作系统中的文件系统在管理磁盘文件时以
4KB大小为一个管理单元,称为"数据块",但是在数据库的应用场景里,查询时数据量都比较大,如果也使用4KB做数据存储的最小的单元,就显的有点小了,同时会造成频繁的磁盘I/O,导致降低效率;所以
MySQL根据自身情况定义了大小为16KB的页,做为磁盘管理的最小单位;每次内存与磁盘的交互至少读取一页,所以在磁盘中每个页内部的地址都是连续的,之所以这样做,是因为在使用数据的过程中,根据局部性原理,将来要使用的数据大概率与当前访问的数据在空间上是临近的,所以一次从磁盘中读取一页的数据放入内存中,当下次查询的数据还在这个页中时就可以从内存中直接读取,从而减少磁盘
I/O,提高性能。
总结:
MySQL根据自身的应用场景使用页做为数据管理单元,最主要的目的就是减少磁盘I/O,提高性能。
2.3.1 什么是局部性原理?
局部性原理是指程序在执行时呈现出局部性规律,在一段时间内,整个程序的执行仅限于程序中的某一部分。相应地,执行所访问的存储空间也局限于某个内存区域,局部性通常有两种形式:时间局部性和空间局部性。
- 时间局部性(
Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。- 空间局部性(
Spatial Locality):将来要用到的信息大概率与正在使用的信息在空间地址上是临近的。
2.4 数据页有哪些基本特性是必须要掌握的? - 页
页的
16KB的大小是MySQL的一个默认设置,可以适用于大多数场景,当然也可以根据自己的实际业务场景进行修改页的大小,通过系统变量innodb_page_size进行调整与查看,在调整页大小的时候需要保证设置的值是操作系统"数据块"4KB的整数倍,从而保证通过操作系统和磁盘交互时"数据块"的完整性,不被分割或浪费,所以规定了innodb_page_size可以设置的值,分别是4096、8192、16384、32768、65536,对应4KB、8KB、16KB、32KB、64KB。每一个页中即使没有数据也会使用
16KB的存储空间,同时与索引的B+树中的节点对应,后续在索引专题中详细讲解B+树的内容,查看页的大小,可以通过系统变量innodb_page_size查看。
mysql
mysql> SHOW VARIABLES LIKE 'innodb_page_size';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.01 sec)
mysql>
在不同的使用场景中,页的结构也有所不同,在
MySQL中有多种不同类型的页,但不论哪种类型的页都会包含页头(File Header)和页尾(File Trailer),在这页头和页尾之间的页主体信息根据不同的类型有不同的结构,最常用的就是用来存储数据和索引的"索引页",也叫做"数据页",页的主体信息使用数据"行"进行填充,行的结构我们在下面的章节中进行详细介绍,页的基本结构如下图所示:

2.5 查询的数据超过一页的大小,怎么提高查询效率 ?区
要解答这个问题,我们先要弄明白前置的几个小问题,首先通过前面的内容,我们了解到磁盘中每个页内部的地址都是连续的,那么我们可以继续提问:
- 不同的页在磁盘中是不是连续的?
- 如果页不连续对访问效率是否有影响?
InnoDB如何保证页在磁盘中的连续性?解决以上三个小问题之后当前的问题自然也就解决了。
2.5.1 不同的页在磁盘中是不是连续的呢?
- 答案是不一定,在不做任何控制的情况下,不同页在磁盘中申请的地址大概率是不连续的。
- 我们可以很快的分析出来连续的地址对查询效率的影响,如果页在磁盘中可以被连续读取,那么查询效率就高,否则果询效率就低。
2.5.2 为什么不连续的地址会降低查询的效率?
当存储介质是机械硬盘时,访问不连续的地址会带来磁盘寻址的开销,也就是磁头在不同盘面、磁道和扇区的机械转动,这个过程称为磁盘随机访问,非常影响效率,磁盘结构如下图所示:

经过以上的分析,当查询的数据大于一页时不加任何控制会产生磁盘随机访问,这个是影响查询效率的主要因素,那么现在怎么提高查询效率的问题就变成了,页在磁盘中是否连续的问题,我们换个问法。
2.5.3 InnoDB如何保证页在磁盘中的连续性?
为了解决磁盘随机访问非常低效的问题,需要尽可能在磁道上读取连续的数据,减少磁头的移动,从而提升效率,
MySQL使用Extent(区) 这个结构来管理页,规定每个区固定大小为1MB,可以存放64个页,这时如果跨页读数据时,大概率都在附近的地址,可以大幅减少碰头移动。提示:我们学习的主要是解决问题的思路,大家要搞懂为什么要有区以及区解决了什么问题,至于区的固定大小不用刻意去记,现阶段是
1MB,以后的版本会不会改变也说不好。同时,如果频繁的读取某个区中的页,可以把整个区都读取出来放入内存中,减少后续查询对磁盘的访问次数,进一步提升效率,如图所示

通过对问题的分析,我们了解到
InnoDB中用来组织页的数据结构--区,并且每个区固定大小为1MB,可以包含64个连续的页,查询的数据超过一页大小时,可能会有以下几种情况:
- 页在区内是相邻的:磁盘顺序
I/O,可以大幅提升效率- 页在区内但不是相邻的:可以大幅减少碰头移动,可以提升效率
- 页在不同的区:还是要发生随机
I/O,不能提升效率
2.5.4 新问题
新创建表时没有数据,或者说有的表只有很少的数据,
1MB的空间用不完,那不是就存在空间浪费的问题吗?是的,的确是这样,
InnoDB在设计时也考虑到了这个问题。
总结:
- 区的特点
每个区固定大小为1MB- 区和页的关系
区是用来管理页的一种数据结构,其中包含若干个页,从而保证页与页之间的连续性