是一个高性能、高可用、高扩展的存储引擎。
InnoDB存储引擎主要由内存池和后台线程构成。
其中,内存池由许多个内存块组成,作用如下:
后台线程的主要作用:
后台线程由很多类型,主要包括:
缓冲池
用于弥补CPU和磁盘速度差距太大的问题,CPU直接操作缓冲,然后由其他线程将在缓冲和磁盘之间做衔接。
缓冲池中的数据类型有索引页、数据页、undo页、插入缓冲、自适应哈希索引、锁信息和数据字典信息等。
LRUList 、Free List 和 Flush List
重做日志缓冲
线程先将重做日志放到这个缓冲区,然后将按一定频率将其刷新到重做日志文件。
额外的内存池
数据结构本身的内存进行分配的时候,先从额外的内存池中进行申请,这里不够,才从缓冲池里申请。
朴素的LRU就是利用一个先进先出的队列,将最近用的使用的页放在队列的前端,最久远使用的页就会被排挤到后面,当缓冲池满了的时候,就将后面的页出队。
提高缓冲区的利用率和降低CPU读取数据的总时间。每次CPU读取数据,会先去缓冲池里找,如果命中了,就直接提交;如果没有,就会去磁盘里提取,然后存储在缓冲区。因为缓冲池的大小是有限的,只能让部分数据存在里面,LRU算法就是确定哪些数据该留在缓冲区,哪些数据该被丢掉。
InnoDB对传统的LRU算法做了一些优化。在LRU队列中加入了midpoint位置,对于新加入的页,不会被直接放大列表头部,而是插入到midpoint的位置,一般默认位置是5/8长度处。midpoint前面的队列称为热点数据,而后面的就是old数据。
InnoDB通过一个时间参数,规定将读取到页等待多久的时间就会被加入到LRU队列的热点部分。
如果采用朴素的LRU算法,将新添加的页直接放到头部,这样,可能会将热点的数据挤出去,从而降低了效率。通过加入midpoint,可以将热点的数据一直维持在midpoint之前的位置,将不常用的数据放在之后,这样,不常用的数据更有可能被先丢出去啊。
而新添加的数据还不知道是不是一个热点的数据,所以先放在midpoint位置上,然后通过midpoint和时间参数的配合,就能判断它是不是热点的。这样热点的数据就尽量不会被刷出。
在上面出现了undo log 和redo log 两个内容,在这里解释区分一下。
数据库通常借助日志来实现事务,常见的有undo log、redo log,undo/redo log都能保证事务特性,undolog实现事务原子性,redolog实现事务的持久性。
undo log
记录中存储的是老版本数据,当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录。
redo log
就是保存执行的SQL语句到一个指定的Log文件,当mysql执行数据恢复时,重新执行redo log记录的SQL操作即可。
作用:
数据库线程需要将脏页从缓存池中刷新到磁盘,如何控制刷新的时间和频率对数据库的性能和防止数据丢失就很重要。
具体的就是每次刷新多少脏页到磁盘,每次读取哪些脏页,什么时候出发刷新。
InnoDB将CheckPoint分为两种:
由多个循环组成,包括主循环、后台循环、刷新循环和暂停循环。
主循环包括两个部分:每秒一次的操作和每十秒一次的操作。
每秒一次的操作包括:
所谓可能,就是不会每次都发生的操作。
每十秒一次的操作包括:
如果没有用户活动或者数据被关闭了,就会切换到这个循环。
执行的操作包括:
如果刷新循环都没有事情可以做,就会被切换到暂停循环,将master thread挂起。
之前的刷新数量都是硬编码,是写死的。就会出现刷新数量低,线程忙不过来的问题。
后来改进这个问题,将刷新的数量与合并插入缓冲的数量设置为百分比,根据系统性能做出更改。还有就是自适应刷新,根据脏页的比例,控制刷新频率。
对于脏页的刷新操作,被从master线程中分离到了单独的page cleaner线程中了。
解决问题:对于使用非聚集索引,插入操作不再是顺序的,需要离散地访问非聚集索引页,由于随机读取导致插入操作的性能下降。
目的:提高非聚集索引插入的性能。
实现原理:对于非聚集索引的插入和更新操作,先判断插入的非聚集索引页是不是在缓冲池中,如果在,就直接插入;如果不在,就先放到一个插入缓冲对象,标记为已插入,然后就等待到以后以一定频率和情况进行真正的插入缓冲和辅助索引页子节点的合并操作。这样可以将多个插入合并到一个操作中,大大提高了非聚集索引的性能。
使用插入缓冲需要两个条件:
插入缓冲的升级版。
包括Insert Buffer、Delete Buffer、Purge Buffer,分别对应INSERT DELETE UPDATE操作的缓冲。
对记录进行UPDATE操作可能分为两个过程:标记已删除,真正删除记录。
数据结构就是一棵B+树。
当辅助索引需要插入到页的时候,如果这个页不在缓冲池中,那么引擎就先构造一个search key,接下来查村Insert Buffer这棵B+树,然后将这个记录插入到树的叶子节点中去。
叶子节点的信息包括记录的表空间ID,页所在的偏移量,记录的插入顺序等。
缓冲中的记录如何合并到真正的辅助索引中呢?
三种情况回进行合并操作:
目的:提高数据的页的可靠性。
工作原理:对缓冲池中的脏页进行刷新的时候不会直接写到磁盘,而是先将脏页复制到内存的doublewrite buffer中,然后通过这个buffer分两次写到共享表空间的物理磁盘上,然后再同步磁盘。
目的:一般通过B+树来查询定位页,查询次数取决于树的高度,一般为三到四层,也就是要查三到四次,而通过哈希索引就只需要查一次就能定位到数据。但是不能为所有数据都建立哈希索引,开销上可能划不来。
作用:引擎对表上各项索引进行查询,如果观察到的建立哈希索引可以带来速度提升,就建立哈希索引,这就是自适应哈希索引。
InnoDB存储引擎会根据访问的频率和模式来自动为某些热点页建立哈希索引。
提高磁盘的操作性能,当前的数据库都是采用异步IO来操作磁盘。
工作原理:当刷新到一个脏页的时候,存储引擎就会顺便检测该页所在区的所有页,如果存在脏页,就一起刷新了,这样可以将多个IO合并为一个IO进行操作,大大提高对机械磁盘的操作性能。
通过这一节内容,很好地理解和总结了InnoDB的相关知识,尤其是LRU、插入缓冲部分,如果学习过操作系统,那么将会对内存管理相关等知识得到一个更全面和深刻的理解。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章