【详解】MySQL的InnoDB存储引擎
目录
1. InnoDB存储引擎体系架构
内存块:
- 维护所有进程/线程需要访问的多个内部数据结构
缓存磁盘的数据
,方便快速的读取,并在磁盘数据修改之前在这里缓存
- 重做日志缓冲
后台线程:
刷新内存池的数据,保证数据是最新的
将已经修改的数据文件保存到磁盘中
保证数据库在发生异常的情况下InnoDB能恢复到正常的状态
- 主要工作在
master thread
中完成
内存
- 内存由
缓冲池
、重做日志缓冲池
和额外的内存池
组成 - 缓冲池是占内存最多的部分,缓存的数据类型有:
索引页
、数据页
、undo页
、插入缓冲
、自适应哈希索引
、存储的锁信息、数据字典信息等
InnoDB存储引擎工作方式
- 将数据库文件按页(每页16k)读取到缓冲池,然后按照最近最少使用的算法(LRU)保留缓存数据。
- 如果数据发生更改,总是
先修改缓存池的页
(脏页),然后再保存在磁盘中
日志缓冲
- 保证
持久性
。即:一旦事务提交, 则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。 - 将重做日志先放入缓冲区,然后保存在重做日志文件
额外的内存池
- 当对一些数据结构分配内存时,从额外的内存池中申请,因为缓冲池中的数据都是有意义的
2 master thread
2.1 源码分析
- 线程优先级别最高。
- 由几个循环组成:主循环(loop)、后台循环(background loop)、刷新循环(flush loop)、暂停循环(suspend loop)。
2.1.1 主循环(loop)
伪代码:
- 大部分操作在这个里面进行,分为两大部分:
每秒操作
和每十秒操作
- 在负载很大时,可能会有
延迟
(delay),每秒操作和每十秒操作可能不准确
每秒一次的操作:
日志缓冲刷新到磁盘
,即使这个事务还没有提交(总是)合并插入缓存
(更新索引)- 至多刷新100个InnoDB的缓冲池中的
脏页数据到磁盘
(可能) - 如果当前没有用户活动,
切换到后台循环
(可能)
综上代码优化为:
每十秒一次的操作:
- 刷新100脏页到磁盘(可能)
- 合并至多5个插入缓存(总是)
- 将日志缓冲刷新到磁盘(总是)
删除无用的Undo页
–在操作任何数据之前,首先将数据备份到一个地方(总是)- 刷新100或者10%脏页到磁盘(总是)
产生一个检查点
–记录哪些日志在数据恢复时需要执行,哪些已经不需要执行
伪代码如下:
2.1.2 background loop
- 数据库没有用户操作时或者数据库关闭时,就会切换到这个循环
执行的操作
- 删除无用的Undo页(总是)
- 合并20个插入缓存(总是)
- 跳回主循环(总是)
- 不断刷新100个页,直到符合条件(可能,跳flush loop中完成)
伪代码:
- 当flush loop没有事情可以做,会切换到suspend loop暂时挂起
2.2 master thread潜在的问题
- 发现InnoDB对IO是有限制的,在缓冲池向磁盘刷新有一定限制
- 如果在密集的写的应用程序中,每秒产生超过100脏页或者超过20个插入语缓存,master thread会
忙不过来
解决
- 合并缓存的数量为innodb_ io_ capacity数值的5%。
- 刷新脏页的数目可以让用户根据磁盘情况设置innodb_ io_ capacity
最终修复后的伪代码:
3. 关键特性
- 插入缓存–性能
- 两次写–可靠性
- 自适应哈希索引
3.1 插入缓存
- 因为主键是表唯一标识,所以插入顺序按照主键递增(自增主键)的顺序插入。
- 因此,插入的聚集索引一般是顺序的,不需要对磁盘随机读取,所以速度很快。
- 但是一个表不止有聚集索引,索引的插入不再是顺序的
聚集索引:
索引中键值的逻辑顺序决定了表中相应行的物理顺序(索引中的数据物理存放地址和索引的顺序是一致的)
非聚集索引:
索引的逻辑顺序与磁盘上的物理存储顺序不同。
- 插入索引对于非聚集索引,不是一次性插入到索引页,先判断索引页是否在缓存池。如果在,直接插入;如果不在,先放入插入缓存,
将多个插入合并在一个中
(因为都是在一个索引页中),在根据磁盘IO情况更新到磁盘中。 索引必须是辅助索引,索引不是唯一的
- 默认最多占一半缓存池空间
缺点:
- 由于并没有及时把索引更新到磁盘中,如果数据库宕机,则
需要很多的时间恢复数据
3.2 两次写
- 当数据库宕机时,数据库可能正在写一个页面,而这个页面只写了一部分,则称之为部分写失效,从而导致数据丢失
- 如果此时直接使用Undo日志,由于页出现了损坏,所以此时是无意的
在执行Undo日志之前,先需要一个页副本用来恢复的没有写之前的状态,再进行重做。
- doublewrite由两部分组成:内存中的doublewrite buffer,物理磁盘共享表中的两个区
在缓冲池脏页刷新时,先将数据拷贝到内存中的doublewrite buffer,然后在写入物理磁盘共享表中的两个区,然后在更新磁盘数据
- 由于doublewrite是连续的,所以对其的IO操作时顺序写的,开销不大
3.3 自适应哈希索引
- 哈希是一种查找办法,常用于join连接操作
- 会监控表上索引的查找,如果建立哈希索引可以提供速度,则建立哈希索引。
- 哈希索引通过缓存池中的B+数构造而来,因此建立速度很快
- 并不是整个表都需要建立哈希索引,InnoDB会根据访问的频率为某些页单独建立哈希索引
4. InnoDB Plugin
- 快速的索引重建
- 更好的多核性能
- 新的页结构
- 页压缩能力
- 更好的BLOB处理能力