MySQL中InnoDB存储引擎的实现和运行原理
InnoDB 存储引擎作为我们最常用到的存储引擎之一,充分熟悉它的的实现和运行原理,有助于我们更好地创建和维护数据库表。
InnoDB 体系架构
InnoDB 主要包括了: 内存池、后台线程以及存储文件。
内存池又是由多个内存块组成的,主要包括缓存磁盘数据、
redo log
缓冲等;后台线程则包括了 :
Master Thread
、IO Thread
以及Purge Thread
等;由 InnoDB 存储引擎实现的表的存储结构文件一般包括表结构文件(.frm)、共享表空间文件(ibdata1)、独占表空间文件(ibd)以及日志文件(redo 文件等)等。
1. 内存池
我们知道,如果客户端从数据库中读取数据是直接从磁盘读取的话,无疑会带来一定的性能瓶颈,缓冲池的作用就是提高整个数据库的读写性能。
客户端读取数据时,如果数据存在于缓冲池中, 客户端就会直接读取缓冲池中的数据,否则再去磁盘中读取;对于数据库中的修改数据,首先是修改在缓冲池中的数据,然后再通过 Master Thread
线程刷新到磁盘上。
理论上来说,缓冲池的内存越大越好。 缓冲池中不仅缓存索引页和数据页,还包括了 undo
页,插入缓存、自适应哈希索引以及 InnoDB
地锁信息等等。
InnoDB 允许多个缓冲池实例,从而减少数据库内部资源的竞争,增强数据库的并发处理能力。
InnoDB
存储引擎会先将重做日志信息放入到缓冲区中,然后再刷新到重做日志文件中。
2. 后台线程
Master Thread
主要负责将缓冲池中的数据异步刷新到磁盘中, 除此之外还包括插入缓存、undo 页的回收等,IO Thread
是负责读写 IO 的线程,而 Purge Thread
主要用于回收事务已经提交了的 undo log
,Pager Cleaner Thread
是新引入的一个用于协助 Master Thread
刷新脏页到磁盘的线程,它可以减轻 Master Thread
的工作压力,减少阻塞。
3. 存储文件
在 MySQL 中建立一张表都会生成一个.frm 文件,该文件是用来保存每个表的元数据信息的,主要包含表结构定义。
在 InnoDB
中,存储数据都是按表空间进行存放的,默认为共享表空间, 存储的文件即为共享表空间文件(ibdata1)。若设置了参数 innodb_file_per_table
为 1,则会将存储的数据、索引等信息单独存储在一个独占表空间,因此也会产生一个独占表空间文件(ibd)。如果你对共享表空间和独占表空间的理解还不够透彻,接下来我会详解。
而日志文件则主要是重做日志文件,主要记录事务产生的重做日志,保证事务的一致性。
InnoDB 逻辑存储结构
InnoDB 逻辑存储结构分为表空间(Tablespace)、段 (Segment)、区 (Extent)、页 Page) 以及行 (row)。
1. 表空间(Tablespace)
InnoDB
提供了两种表空间存储数据的方式,一种是共享表空间,一种是独占表空间。 InnoDB
默认会将其所有的表数据存储在一个共享表空间中,即 ibdata1。
我们可以通过设置 innodb_file_per_table
参数为 1(1 代表独占方式)开启独占表空间模式。开启之后,每个表都有自己独立的表空间物理文件,所有的数据以及索引都会存储在该文件中,这样方便备份以及恢复数据。
2. 段 (Segment)
表空间是由各个段组成的,段一般分为数据段、索引段和回滚段等。我们知道,InnoDB 默认是基于 B + 树实现的数据存储。
这里的索引段则是指的 B + 树的非叶子节点,而数据段则是 B + 树的叶子节点。而回滚段则指的是回滚数据。
3. 区 (Extent) / 页(Page)
区是表空间的单元结构,每个区的大小为 1MB。而页是组成区的最小单元, 页也是 InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。为了保证页的连续性,InnoDB 存储引擎每次从磁盘申请 4-5 个区。
4. 行(Row)
InnoDB 存储引擎是面向列的(row-oriented
),也就是说数据是按行进行存放的,每个页存放的行记录也是有硬性定义的,最多允许存放 16KB/2-200 行,即 7992 行记录。
InnoDB 事务之 redo log 工作原理
InnoDB 是一个事务性的存储引擎, 而 InnoDB 的事务实现是基于事务日志 redo log
和 undo log
实现的。redo log
是重做日志,提供再写入操作,实现事务的持久性;undo log 是回滚日志,提供回滚操作,保证事务的一致性。
redo log 又包括了内存中的日志缓冲(redo log buffer) 以及保存在磁盘的重做日志文件(redo log file),前者存储在内存中,容易丢失,后者持久化在磁盘中,不会丢失。
InnoDB 的更新操作采用的是 Write Ahead Log 策略,即先写日志,再写入磁盘。 当一条记录更新时,InnoDB 会先把记录写入到 redo log buffer
中,并更新内存数据。我们可以通过参数
innodb_flush_log_at_trx_commit
自定义 commit
时,如何将 redo log buffer 中的日志刷新到 redo log file 中。
在这里,我们需要注意的是 InnoDB
的 redo log
的大小是固定的, 分别有多个日志文件采用循环方式组成一个循环闭环,当写到结尾时,会回到开头循环写日志。我们可以通过参数 innodb_log_files_in_group
和 innodb_log_file_size
配置日志文件数量和每个日志文件的大小。
Buffer Pool
中更新的数据未刷新到磁盘中,该内存页我们称之为脏页。 最终脏页的数据会刷新到磁盘中,将磁盘中的数据覆盖,这个过程与 redo log
不一定有关系。
只有当 redo log
日志满了的情况下,才会主动触发脏页刷新到磁盘, 而脏页不仅只有 redo log
日志满了的情况才会刷新到磁盘,以下几种情况同样会触发脏页的刷新:
- 系统内存不足时,需要将一部分数据页淘汰掉,如果淘汰的是脏页,需要先将脏页同步到磁盘;
- MySQL 认为空闲的时间,这种情况没有性能问题;
- MySQL 正常关闭之前,会把所有的脏页刷入到磁盘,这种情况也没有性能问题。
在生产环境中,如果我们开启了慢 SQL 监控,你会发现偶尔会出现一些用时稍长的 SQL。 这是因为脏页在刷新到磁盘时可能会给数据库带来性能开销,导致数据库操作抖动。
LRU 淘汰策略
以上我们了解了 InnoDB 的更新和插入操作的具体实现原理,接下来我们再来了解下它的实现和优化方式。
InnoDB 存储引擎是基于集合索引实现的数据存储,也就是除了索引列以及主键是存储在 B + 树之外, 其它列数据也存储在 B + 树的叶子节点中。而这里的索引页和数据页都会缓存在缓冲池中,在查询数据时,只要在缓冲池中存在该数据,InnoDB
就不用每次都去磁盘中读取页,从而提高数据库的查询性能。
虽然缓冲池是一个很大的内存区域,但由于存放了各种类型的数据, 加上存储数据量之大,缓冲池无法将所有的数据都存储在其中。因此,缓冲池需要通过 LRU 算法将最近且经常查询的数据缓存在其中,而不常查询的数据就淘汰出去。
InnoDB 对 LRU 做了一些优化, 我们熟悉的 LRU 算法通常是将最近查询的数据放到 LRU 列表的首部,而 InnoDB 则是将数据放在一个 midpoint 位置,通常这个 midpoint 为列表长度的 5/8。
这种策略主要是为了避免一些不常查询的操作突然将热点数据淘汰出去,而热点数据被再次查询时,需要再次从磁盘中获取,从而影响数据库的查询性能。
如果我们的热点数据比较多,我们可以通过调整 midpoint 值来增加热点数据的存储量,从而降低热点数据的淘汰率。
总结
以上 InnoDB
的实现和运行原理到这里就介绍完了。 总的来讲,作为开发工程师,我们应该掌握数据库几个大的知识点,然后再深入到数据库内部实现的细节,这样才能避免经常写出一些具有性能问题的 SQL,培养调优数据库性能的能力。
看完三件事️
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注公众号 『 阿风的架构笔记 』,不定期分享原创知识。
- 同时可以期待后续文章ing
- 关注后回复【666】扫码即可获取架构进阶学习资料包
MySQL中InnoDB存储引擎的实现和运行原理的更多相关文章
- MySql中innodb存储引擎事务日志详解
分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...
- mysql中InnoDB存储引擎的行锁和表锁
Mysql的InnoDB存储引擎支持事务,默认是行锁.因为这个特性,所以数据库支持高并发,但是如果InnoDB更新数据的时候不是行锁,而是表锁的话,那么其并发性会大打折扣,而且也可能导致你的程序出错. ...
- MySQL数据库InnoDB存储引擎多版本控制(MVCC)实现原理分析
文/何登成 导读: 来自网易研究院的MySQL内核技术研究人何登成,把MySQL数据库InnoDB存储引擎的多版本控制(简称:MVCC)实现原理,做了深入的研究与详细的文字图表分析,方便大家理解I ...
- MySQL中InnoDB存储引擎中的哈希算法
InnoDB存储引擎使用哈希算法来对字典进行查找,其冲突机制采用链表方式,哈希函数采用除法散列方式.对于缓冲池页的哈希表来说,在缓冲池中的Page页都有一个chain指针.它指向相同哈希函数值的页的. ...
- 转!!MySQL中的存储引擎讲解(InnoDB,MyISAM,Memory等各存储引擎对比)
MySQL中的存储引擎: 1.存储引擎的概念 2.查看MySQL所支持的存储引擎 3.MySQL中几种常用存储引擎的特点 4.存储引擎之间的相互转化 一.存储引擎: 1.存储引擎其实就是如何实现存储数 ...
- MySQL数据库InnoDB存储引擎中的锁机制
MySQL数据库InnoDB存储引擎中的锁机制 http://www.uml.org.cn/sjjm/201205302.asp 00 – 基本概念 当并发事务同时访问一个资源的时候,有可能 ...
- mysql之innodb存储引擎
mysql之innodb存储引擎 innodb和myisam区别 1>.InnoDB支持事物,而MyISAM不支持事物 2>.InnoDB支持行级锁,而MyISAM支持表级锁 3>. ...
- MySQL数据库InnoDB存储引擎
MySQL数据库InnoDB存储引擎Log漫游 http://blog.163.com/zihuan_xuan/blog/static/1287942432012366293667/
- 在MySQL的InnoDB存储引擎中count(*)函数的优化
写这篇文章之前已经看过了很多数据库方面的优化内容,大部分都是加索引.使用事务.要什么select什么等等.然而,只是停留在阅读的层面上,很少有实践,因为没有遇到真实的项目,一切都是纸上谈兵.实践是检验 ...
随机推荐
- editorconfig、eslint、prettier三者的区别、介绍及使用
每次搭建新项目都少不了这些工具,但时间一久就忘记了,下次搭新项目时又要四处查官方文档,因此特此记录,主要内容是对这三个工具的理解,以及具体使用方式 editorconfig 理解 先看官网的定义: E ...
- 记一次 医院.NET公众号系统 线程CPU双高分析
一:背景 1. 讲故事 上周四有位朋友加wx咨询他的程序出现 CPU + 线程 双高的情况,希望我能帮忙排查下,如下图: 从截图看只是线程爆高,没看到 cpu 爆高哈,有意思的是这位朋友说他: 一直在 ...
- WordPress 缩率图学习笔记
WordPress 缩率图学习笔记 Wordpress在生成缩略图的过程中,有两种不同的规则 缩放模式:缩放模式就是将图片等比例缩小,且新生成的缩略图长度或高度两者之中,有一个是你设置的缩略图的尺寸 ...
- video播放视频以及相关事件
<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Conten ...
- 阿里早期Android加固代码的实现分析
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78320445 看雪上有作者(寒号鸟二代)将阿里移动早期的Android加固进行了逆 ...
- POJ 3228 二分最大流
题意: 给你N个位置,每个位置都有金矿数量和仓库数量,然后位置和位置之间的距离给了出来,最后问你吧所有的金矿都放到库里面走的路径 最长的最短 是多少? 思路: 比较简单的一个题, ...
- Windows核心编程 第十七章 -内存映射文件(下)
17.3 使用内存映射文件 若要使用内存映射文件,必须执行下列操作步骤: 1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件. 2) 创建一个文件映射内核对象,告诉系统该 ...
- Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)
SHADOW SSDT HOOK HOOK 和 UNHOOK SHADOW SSDT 跟之前的 HOOK/UNHOOK SSDT 类似,区别是查找SSSDT的特征码,以及根据索引计算函数地址的公式,还 ...
- Windows核心编程 第四章 进程(中)
4.2 CreateProcess函数 可以用C r e a t e P r o c e s s函数创建一个进程: BOOL CreateProcessW( _In_opt_ LPCWSTR lpAp ...
- 【CSS】CSS3从入门到深入(复习查漏向
CSS3从入门到深入(复习查漏向 pre_section CSS:层叠样式表,决定网页表现 网页为多层结构,CSS为每一层设置样式,最后显示最上一层 CSS语句 = 选择器 + 声明块 形式 内联样式 ...