MySQL InnoDB存储引擎架构学习总结

凡事皆有因果。

最近了看了一些InnoDB架构的东西,从宏观来看,所有的架构设计都是为了使系统更加快速和稳定,所以简单总结一下,捋一捋InnoDB架构里面的因果关系。

忘记在哪看的了,记得里面有一句话是这样说的“缓存技术可能是最伟大的发明”。缓存的产生是为了解决通信的介质之间的速度鸿沟。InnoDB缓冲池也是为了解决这个问题,当我们从数据库读取数据的时候,如果在缓冲中没有相应的信息,就在磁盘获取,并且放在缓存中,下次再访问相同的数据直接从缓存返回。如果我们更新或删除数据,那么先在缓冲中进行操作,然后再通过一定的频率将改变同步到磁盘。

从读取数据说起,我们读取的数据太多了,缓存已经存不下了,那怎么办呢?可以扩大缓存,也可以清空原来缓存中的数据。实际应用中这两种方法都会使用,前者不说了,后者如何清除缓存中的数据呢?LRU算法就是为此产生的。

但是LRU算法并不是完全适合这种应用场景,比如我扫描了一个很大的表,这个扫描可能会把缓存中的热数据挤出来,如何解决这种情况呢,InnoDB对LRU算法做了更改,添加了midpoint insertion strategy,即让数据默认插在尾部位置,并且可通过参数设置让热数据的清除更加可控。

当我们读取的某一些数据非常频繁,InnoDB会通过监控和计算为这个等值查询自动添加索引,这就是自适应哈希索引。

当我们读取的数据处在其他会话的事务中的时候怎么办呢?这就产生了隔离级别,也就是说不同的隔离级别对待这种访问是不同的,可以根据自己的应用自行设置。

如果我们访问的数据改变了,但是事务还没有提交,这就用到了Undo log,当我们需要访问原始数据的时候,通过行内部的指针指向Undo log的原始数据,返回给客户端。

接下来说说插入,当我们插入数据的时候,如果主键是随机的,那么会产生随机读取索引页的情况(B+tree的索引的顺序性),从而会使插入数据性能下降。同时因为辅助索引都会关联主键索引,这也会产生网上常说的“索引太多会影响插入性能”。这时候就产生了插入缓冲,通过将多次插入合并为单次插入来增加数据库的插入性能。插入缓冲中的数据冲刷到磁盘的过程中可能会出现问题,为了保证数据的完整性,InnoDB添加了dobulewrite策略,即在写入数据之前先写到doublewrite buffer和共享表空间,然后写入磁盘。

针对InnoDB这样的事务型的存储引擎,当我们修改数据的时候,如果中间宕机了,那我们的数据就会有问题,这时候用到了Redo log,和Redo log缓冲。当我们写数据的时候先写到Redo log缓冲中,然后再通过一定的频率刷新到Redo log(即Write Ahead Log策略),服务器宕机再启动的时候,会自动通过Redo log还原信息。这也就是事务特性ACID中的D(持久性)。

数据更新导致内存中的数据与磁盘里面的数据不同,也就产生了赃页,赃页也是通过一定的频率刷新到磁盘,其中一种情况就是缓冲池中空闲页不足100。这样就保证了缓冲池中有可用的空闲页,整个流程形成了一个环。

因为InnoDB架构中有很多的线程,每个线程负责不同的工作,例如:Purge线程用来回收Undo log,Page Cleaner线程用来刷新赃页。因此应运而生了异步I/O(只发请求,不等待IO),提高磁盘操作效率。

(完)