mysql--InnDB存储引擎详解

一、概述

InnDB存储引擎是MySQL 5.5 版本开始是默认的表存储引擎(之前的版本 InnoDB存储引擎仅在 Windows 下为默认的存储引擎)。该存储引擎是第一个完整支持 ACID 事务的 MySQL 存储引擎,其特点是行锁设计、支持 MVCC、支持外键、提供一致性非锁定读,同时被设计用来最有效地利用以及使用内存和 CPU。

二、InnDB体系架构

InnoDB存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池,负责如下工作∶

(1)维护所有进程/线程需要访问的多个内部数据结构。

(2)缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存。

(3)重做日志(redo log)缓冲。

1. 后台线程

InnoDB 存储引擎是多线程的模型,因此其后台有多个不同的后台线程,负责处理不同的任务

后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB 能恢复到正常运行状态。

分类:

(1)Master Thread

Master Thread 是一个非常核心的后台线程,具有最高的优先级,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲(INSERT BUFFER)、 UNDO 页的回收等

(2)IO Thread

在 InnoDB 存储引擎中大量使用了 AIO(Async IO)来处理写IO请求,这样可以极大提高数据库的性能。而 IO Thread 的工作主要是负责这些 IO 请求的回调(call back)处理

(3)Purge Thread

事务被提交后,其所使用的 undolog 可能不再需要,因此需要 PurgeThread 来回收已经使用并分配的 undo 页

(4)Page Cleaner Thread

Page Cleaner Thread是在 InnoDB 1.2.x版本中引入的。其作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。而其目的是为了减轻原 Master Thread 的工作及对于用户查询线程的阻塞,进一步提高 InnoDB 存储引擎的性能。

 

2.内存

内存数据对象:

(1)缓冲池

InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可将其视为基于磁盘的数据库系统。在数据库系统中,由于 CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。 缓冲池简单来说就是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程称为将页"FIX"在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。 对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这里需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为 Checkpoint 的机制刷新回磁盘

从InnDB 1.0x版本开始允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。这样做的好处是减少数据库内部的资源竞争,增加数据库的并发处理能力,不过默认是1不开启

缓冲区更新逻辑

通常来说,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的。即最频繁使用的页在 LRU列表的前端,而最少使用的页在 LRU 列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放 LRU 列表中尾端的页

(2)重做日志缓冲

InnoDB 存储引擎的内存区域除了有缓冲池外,还有重做日志缓冲(redo log buffer)。InnoDB存储引擎首先将重做日志信息先放入到这个缓冲区,然后按一定频率将其刷新到重做日志文件。重做日志缓冲一般不需要设置得很大,因为一般 情况下每一秒钟会将重做日志缓冲刷新到日志文件,因此用户只需要保证每秒产生的事务量在这个缓冲大小之内即可。

因为存在缓存页,所以一旦发生冗机那么就会造成最近的缓存页丢失,所以重做日志作用就是当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时刻

(3)额外的内存池

InnoDB 存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行的。在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从缓冲池中进行申请。例如,分配了缓冲池(innodb buffer pool),但是每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象(buffer control block),这些对象记录了一些诸如 LRU、锁、等待等信息,而这个对象的 内存需要从额外内存池中申请。因此,在申请了很大的 InnoDB 缓冲池时,也应考虑相应地增加这个值

3.Checkpoint 技术

当数据库运行了几个月甚至几年时,这时发生宕机,重新应用重做日志的时间会非常久,此时恢复的代价也会非常大。 因此 Checkpoint (检查点)技术的目的是解决以下几个问题

(1)缩短数据库的恢复时间

(2)缓冲池不够用时,将脏页刷新到磁盘

(3)重做日志不可用时,刷新脏页

当数据库发生宕机时,数据库不需要重做所有的日志,因为 Checkpoint 之前的页都已经刷新回磁盘。故数据库只需对 Checkpoint 后的重做日志进行恢复。这样就大大缩短了恢复的时间。 此外,当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行 Checkpoint,将脏页也就是页的新版本刷回磁盘。

三、InnDB 关键特性

1.插入缓冲( Insert Buffer)

 Insert Buffer可能是 InnoDB 存储引擎关键特性中最令人激动与兴奋的一个功能。不过这个名字可能会让人认为插人缓冲是缓冲池中的一个组成部分。其实不然,InnoDB 缓冲池中有 Insert Buffer 信息固然不错,但是 Insert Buffer并不是缓存的一部分 而是和数据页一样,也是物理页的—个组成部分。在 InnoDB 存储引擎中,主键是行唯一的标识符。通常应用程序中行记录的插人顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引(Primary Key)一般是顺序的,不需要磁盘的随机读取。但是非聚集索引因为B+树的特性所以插入是离散的,耗时较长,因此InnoDB 存储引擎开创性地设计了Insert Buffer,对于非聚集索引的插入或更新操作,不是每一次直接插入索引页.而是先判断插入的非聚集索引页是否在缓冲池中.如果在,则直接插入,如果不再,则先放入一个插入缓冲区中.然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作.

何为顺序存储?

主键是递增的所以是顺序存储的,其他索引的索引值一般都不会是递增所以是非顺序存储,不过也有特殊情况比如创单时间字段建索引,一般插入都是按照时间递增的

使用条件:

(1)索引是非聚集索引(辅助索引)

(2)索引不是唯一索引

用还书的例子来说,还一本书A到图书馆,管理员要判断一下这本书是不是唯一的,他在柜台上是看不到的,必须爬到指定位置去确认,这个过程其实已经产生了一次IO操作,相当于没有节省任何操作。

所以这个buffer只能处理非唯一的插入,不要求判断是否唯一。聚集索引就不用说了,它肯定是唯一的,mysql现在还只能通过主键聚集。
 

加缓冲区的好处

无需每次插入都更新数据,而是先存在缓冲区,等不忙时一起操作,

Change Buffer

InnoDB 从1.0.x 版本开始引入了Change Buffer,可将其视为 Insert Buffer 的升级。

从这个版本开始,InnoDB存储引擎可以对 DML 操作——INSERT、DELETE、UPDATE都进行缓冲,他们分别是∶ Insert Buffer、Delete Buffer、Purge buffer。

原理和之前 Insert Buffer几乎一样,Change Buffer 适用的对象依然是非唯一的辅助索引。对一条记录进行 UPDATE 操作可能分为两个过程∶

(1)将记录标记为已删除;

(2)真正将记录删除。

因此 Delete Buffer 对应 UPDATE 操作的第一个过程,即将记录标记为删除。Purge Buffer对应 UPDATE 操作的第二个过程,即将记录真正的删除。

2.两次写

如果说 Insert Buffer 带给 InnoDB存储引擎的是性能上的提升,那么 doublewrite(两次写)带给 InnoDB 存储引擎的是数据页的可靠性。 当发生数据库宕机时,可能 InnoDB 存储引擎正在写入某个页到表中,而这个页只写了一部分,比如 16KB 的页,只写了前 4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。在 InnoDB 存储引擎未使用 doublewrite技术前,曾经出现过因为部分写失效而导致数据丢失的情况。

前面说过可以通过重做日志进行恢复。这是一个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作,如本来要写'aaaaaaa',但是写到第四个a时就发生了崩溃,这个页本身已经发生了损坏,页中的数据为aaaa,再对其进行重做是没有意义的因为已经存在脏数据了,需要先将脏数据干掉再恢复。这就是说,在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是 doublewrite。

3.自适应hash

众所周知,InnoDB使用的索引结构是B+树,但其实它还支持另一种索引:自适应哈希索引。 B+ 树的查找次数,取决于 B+ 树的高度生产环境一般为3-4层,而哈希在一般情况下这种查找的时间复杂度为 O(1),InnoDB 存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引(AHI)。 AHI 是通过缓冲池的 B+ 树页构造而来,因此建立的速度很快,而且不需要对整张表构建哈希索引。InnoDB 存储引擎会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引。AHI的状态是默认打开的

4.异步IO

为了提高磁盘操作性能,当前的数据库系统都采用异步 IO (Asynchronous IO, AIO)的方式来处理磁盘操作。InnoDB 存储引擎亦是如此。与 AIO 对应的是 Sync IO,即每进行一次 IO操作,需要等待此次操作结束才能继续接下来的操作。但是如果用户发出的是一条索引扫描的查询,那么这条 SQL 查询语句可能需要扫描多个索引页,也就是需要进行多次的 IO 操作。在每扫描一个页并等待其完成后再进行下一次的扫描,这是没有必要的。用户可以在发出一个 IO 请求后立即再发出另一个 IO 请求,当全部 IO 请求发送完毕后,等待所有IO 操作的完成,这就是 AIO。 AIO 的另一个优势是可以进行 IO Merge 操作,也就是将多个 IO 合并为1个 IO,这样可以提高 IOPS 的性能。例如用户需要访问页的(space,page_no)为∶ (8,6)、(8,7),(8,8)每个页的大小为 16KB,那么同步IO需要进行 3 次 IO 操作。而 AIO 会判断到这三个页是连续的(显然可以通过(space,page no)得知)。因此 AIO底层会发送一个IO请求,从(8,6)开始,读取 48KB的页。

5.刷新临接页

InnoDB 存储引擎还提供了Flush Neighbor Page(刷新邻接页)的特性。其工作原理为∶当刷新一个脏页时,InnoDB 存储引擎会检测该页所在区(extent)的所有页,如果是脏页,那么一起进行刷新。这样做的好处显而易见,通过 AIO 可以将多个IO 写入操作合并为一个IO操作,故该工作机制在传统机械磁盘下有着显著的优势。固态硬盘有着较高的 IOPS一般会关闭该特性

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值