InnoDB架构详解

什么是存储引擎?

Mysql的官方解释:

存储引擎是 MySQL 组件,用于处理不同表类型的 SQL 操作。

这句解释简单的不能再简单了,说白了就是Mysql中的一个组件,那为什么需要这个组件呢,为什么不把存储引擎放在服务层里呢?

那还需要看官方的另一个解释:

MySQL Server 使用可插拔的存储引擎架构,使存储引擎能够加载到正在运行的MySQL 服务器中和从中卸载。

MySQL 可插拔存储引擎架构使数据库专业人员能够为特定应用程序需求选择专门的存储引擎,同时完全无需管理任何特定应用程序编码要求。MySQL服务器架构将应用程序员和 DBA 与存储级别的所有低级实现细节隔离开来,提供一致且简单的应用程序模型和API。因此,尽管不同存储引擎具有不同的功能,但应用程序不受这些差异的影响。

这样看,官方解释的还是很明确的,就是为了和应用层去做隔离,使得程序员可以根据自己的业务需要去更换不同的存储引擎。

由此又引出一个问题,不同的存储引擎有那些不同呢?首先要知道Mysql支持了那些存储引擎。

存储引擎都有啥?

使用SHOW ENGINES查看的你的Mysql支持的存储引擎
在这里插入图片描述
这样一看,Mysql支持的存储引擎还不少,但这里就不一一介绍了,还是主要介绍最常见的三个:

InnoDB:MySQL 5.7 中的默认存储引擎。 InnoDB是 MySQL 的事务安全(符合 ACID)存储引擎,具有提交、回滚和崩溃恢复功能来保护用户数据。 InnoDB行级锁定(不升级为更粗粒度的锁定)和 Oracle 风格一致的非锁定读取提高了多用户并发性和性能。InnoDB将用户数据存储在聚集索引中,以减少基于主键的常见查询的I/O。为了维护数据完整性, InnoDB还支持FOREIGN KEY引用完整性约束。

MyISAM:这些表占用空间很小。 表级锁定 限制了读/写工作负载的性能,因此它通常用于 Web 和数据仓库配置中的只读或以读取为主的工作负载。

Memory:将所有数据存储在 RAM中,以便在需要快速查找非关键数据的环境中进行快速访问。这种发动机以前称为HEAP发动机。它的用例正在减少;InnoDB其缓冲池内存区域提供了一种通用且持久的方式来将大部分或所有数据保存在内存中,并NDBCLUSTER为庞大的分布式数据集提供快速的键值查找。

为什么MYSQL选择了InnoDB作为默认的存储引擎?

到这里突然想到一个很经典的面试题:
有很多面试官在听你提到InnoDB时,就会让你说一下InnoDB和MyISAM的区别,这里我也总结一下:

  1. 事务:InnoDB支持事务,MyISAM不支持事务
  2. 外键:InnoDB支持外键,MyISAM不支持
  3. 锁:InnoDB支持行级锁,MyISAM只支持表级锁
  4. 存储文件:InnoDB的表记录和索引存在一个文件中,索引的叶子结点存储量整条记录的数据;MyISAM的表记录和索引分成了两个文件,索引的叶子结点存储的是表记录的地址
  5. 查询count性能:MyISAM查询全表的count时性能更好,因为维护了这个count(注意:如果有where条件时就和InnoDB一样了),InnoDB在查询count时需要全表扫描

SO,我认为,Mysql的默认存储引擎选择了InnoDB也是这些原因吧,毕竟现在的业务逻辑也是越来越复杂了,必然涉及到事务问题和性能问题。

InnoDB架构了解一下?

接下来可以进入这篇文章的主题了,有个十分经典的InnoDB架构图:
在这里插入图片描述
这是Mysql官方给出的InnoDB的架构图,这应该再准确不过了。(强烈建议大家一定要把这张图保存下来,及时翻阅)
由图可以看出整个架构分成了两个部分:

  • 内存结构
  • 磁盘结构

接下来可以逐个了解一下其中的各个组件。

内存结构

Buffer Pool

缓冲池是主内存中的一个区域,用于在 InnoDB访问时缓存表和索引数据。缓冲池允许直接从内存访问经常使用的数据,从而加快处理速度。在专用服务器上,多达 80% 的物理内存通常分配给缓冲池。

缓冲池为了提高大量读取操作的效率,选择按页的方式存储,一页可包含多条记录;同时为了缓存管理的效率,采用了链表的结构,配合LRU算法保证链表中的数据是热点数据。(当然这里的LRU并不是标准的,InnoDB在LRU的基础上做了改进)

Change Buffer

更改缓冲区是一种特殊的数据结构,当二级索引(即普通索引)页不在缓冲池中时,它会缓存对二级索引页的更改 。可能由INSERT、 UPDATE或 DELETE操作 (DML)导致的缓冲更改,稍后在其他读取操作将页面加载到缓冲池时合并。

在这里插入图片描述
InnoDB为了提高读操作的性能,使用了缓冲池进行优化,那么针对写操作的优化就是引入了更改缓冲区。

但要清楚知道这是针对二级索引的优化。(为什么?~后续会出专文,此处以了解为主)

Log Buffer

日志缓冲区是保存要写入磁盘上日志文件的数据的内存区域。日志缓冲区大小由innodb_log_buffer_size变量定义 。默认大小为 16MB。日志缓冲区的内容会定期刷新到磁盘。大型日志缓冲区使大型事务能够运行,而无需在事务提交之前将重做日志(redo log)数据写入磁盘。因此,如果您有更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘 I/O。

在这里插入图片描述
innodb_flush_log_at_trx_commit变量控制日志缓冲区的内容如何写入和刷新到磁盘。该 innodb_flush_log_at_timeout变量控制日志刷新频率。

在这里插入图片描述

Adaptive Hash Index

MySQL 索引,不管是在磁盘里,还是被 load 到内存后,都是 B+ 树,B+ 树的查找次数取决于树的深度。你看,数据都已经放到内存了,还不能“一下子”就找到它,还要“几下子”,这空间牺牲的是不是不太值得?

尤其是那些频繁被访问的数据,每次过来都要走 B+ 树来查询,这时就会想到,我用一个指针把数据的位置记录下来不就好了?

这就是「自适应哈希索引」(Adaptive Hash Index)。自适应,顾名思义,MySQL 会自动评估使用自适应索引是否值得,如果观察到建立哈希索引可以提升速度,则建立。

自适应哈希索引,简单来讲就是索引的索引。就是InnoDB为了提高查询热点数据索引的性能,采用的一种自动创建哈希索引的方式,不需要人工参与创建,所以称之为自适应哈希索引。

这也是为什么有的人觉得InnoDB不支持哈希索引,但是有的人认为InnoDB支持哈希索引的原因。

磁盘结构

Tables

毋庸置疑,磁盘上必然存在表数据

Indexes

同上,索引数据和表数据是必不可少的

Tablespaces

以上是我摘抄的Mysql官网的部分解释,我自己对这部分其实也不是很了解,这里贴出来只是为了有个大概的了解,如果十分感兴趣,可以去Mysql官网查看学习一下。

  1. The System Tablespace :系统表空间

系统表空间是InnoDB数据字典、双写缓冲区、更改缓冲区和撤消日志的存储区域 。如果表是在系统表空间中创建的,而不是在每个表文件或通用表空间中创建,则它还可能包含表和索引数据。

  1. File-Per-Table Tablespaces :每个表文件表空间

每个表的文件表空间包含单个InnoDB表的数据和索引 ,并存储在文件系统上的单个数据文件中。

  1. General Tablespaces:通用表空间

通用表空间是InnoDB 使用CREATE TABLESPACE语法创建的共享表空间

  1. Undo Tablespaces:撤销表空间

撤消表空间包含撤消日志,这是包含有关如何撤消事务对聚集索引记录的最新更改的信息的记录集合。
撤消日志默认存储在系统表空间中,但也可以存储在一个或多个撤消表空间中。使用撤消表空间可以减少任何一个表空间中撤消日志所需的空间量。撤消日志的 I/O 模式也使撤消表空间成为SSD存储的理想选择 。

  1. The Temporary Tablespace:临时表空间

非压缩、用户创建的临时表和磁盘内部临时表在共享临时表空间中创建
临时表空间在正常关闭或中止初始化时被删除,并在每次服务器启动时重新创建。临时表空间在创建时会收到一个动态生成的空间 ID。如果无法创建临时表空间,则拒绝启动。如果服务器意外停止,则不会删除临时表空间。在这种情况下,数据库管理员可以手动删除临时表空间或重新启动服务器,服务器会自动删除并重新创建临时表空间。

其中,我们平时创建的表的数据,可以存放到 The System Tablespace 、File-Per-Table Tablespaces、General Tablespace 三者中的任意一个地方,具体取决于你的配置和创建表时的 sql 语句。

InnoDB Data Dictionary

InnoDB数据字典由包含元数据的用于跟踪对象的如表,索引,和表中的列的内部系统表。元数据物理上位于InnoDB系统表空间中。由于历史原因,数据字典元数据与存储在InnoDB表元数据文件(.frm文件)中的信息有一定程度的重叠

Doublewrite Buffer

如果说 Change Buffer 是提升性能,那么 Doublewrite Buffer 就是保证数据页的可靠性。

前面提到过,MySQL 以「页」为读取和写入单位,一个「页」里面有多行数据,写入数据时,MySQL 会先写内存中的页,然后再刷新到磁盘中的页。

这时问题来了,假设在某一次从内存刷新到磁盘的过程中,一个「页」刷了一半,突然操作系统或者 MySQL 进程奔溃了,这时候,内存里的页数据被清除了,而磁盘里的页数据,刷了一半,处于一个中间状态,不尴不尬,可以说是一个「不完整」,甚至是「坏掉的」的页。

有同学说,不是有 Redo Log 么?其实这个时候 Redo Log 也已经无力回天,Redo Log 是要在磁盘中的页数据是正常的、没有损坏的情况下,才能把磁盘里页数据 load 到内存,然后应用 Redo Log。而如果磁盘中的页数据已经损坏,是无法应用 Redo Log 的。

所以,MySQL 在刷数据到磁盘之前,要先把数据写到另外一个地方,也就是 Doublewrite Buffer,写完后,再开始写磁盘。Doublewrite Buffer 可以理解为是一个备份(recovery),万一真的发生 crash,就可以利用 Doublewrite Buffer 来修复磁盘里的数据。

Redo Log

重做日志是一种基于磁盘的数据结构,用于在崩溃恢复期间纠正不完整事务写入的数据。在正常操作期间,重做日志对由 SQL 语句或低级 API 调用产生的更改表数据的请求进行编码。在初始化期间和接受连接之前,会自动重放在意外关闭之前未完成更新数据文件的修改。有关重做日志在崩溃恢复中的作用的信息

Undo Logs

回滚日志,记录的是数据被修改之前的信息,比如:delete一条数据,在undolog里会记录一条insert记录;update一条数据,会记录一条update到原始数据的记录

絮叨一下

以上是我在学习过程中想要记录和分享的,我的学习方式就是分块学习,但首先你总要知道有那些块吧。所以我先学习了整体的架构,然后再选择某一块去深入挖掘,这也是深受我领导的指点吧,等学着学着就会发现,一个一个的知识点就随之出现了,而我们需要做的就是把所有的知识去串起来,自己总结或者跟其他同学讲一遍,只有能讲出来才是真的学会了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值