深入理解MySQL——LRU、Free和Flush 链表

首先,缓冲池申请的内存空间一定是页大小(默认16KB)的倍数,换句话说,虽然缓冲池是一块很大的内存区域,然而在使用时是根据固定的页大小进行管理的。如图1-1所示∶
深入理解MySQL——LRU、Free和Flush 链表_第1张图片
缓冲池有一个 free 链表,其中保存着未被使用的内存页空间。当 free 链表中的页都已分配完毕,当再要申请空间时,则需要根据LRU(Latest Recent Used 最近最少使用)算法淘汰已经使用的页。

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

在InnoDB存储引擎中,其同样使用 LRU 算法对缓冲池进行管理。稍有不同的是 InnoDB存储引擎对传统的LRU算法做了一些优化。在InnoDB的存储引擎中,LRU链表中还加入了midpoint 位置,新读取到的页,虽然是最新访问的页,但并不是直接放入到LRU 链表的首部,而是放入到LRU链表的 midpoint 位置。这个算法在 InnoDB存储引擎下称为 midpoint insertion strategy。默认配置下,该位置在 LRU链表长度的 3/8处,如图1-2所示。
图1-2 LRU链表的midpoint位置
那为什么不采用朴素的 LRU 算法,直接将读取的页放入到LRU链表的首部呢?这是因为若直接将读取到的页放入到LRU的首部,那么某些 SOL 操作可能会使得缓冲池中的页从LRU 链表中被刷新出,从而影响缓冲池的效率。常见的这类操作为索引或者数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页通常来说仅在这次查询操作中需要,并不是活跃的热点数据。如果页被放入 LRU 链表的首部,那么非常可能将所需要的热点数据页从LRU链表中移除,而当下一次需要读取该页时,InnoDB存储引擎需要再次访问磁盘,从而导致数据库性能的下降。

此外还需要特别注意的是,有些使用的页并不存放在 LRU 链表中,例如自适应哈希,锁信息。它们虽然同样通过 free 链表申请空间,但是当申请完毕时,其并不放入LRU链表。所以在输出的状态中可以类似如下的内容∶

深入理解MySQL——LRU、Free和Flush 链表_第2张图片
这里LRUlength+Flush list length并不等于Buffer Pool size,还少了505个页。原因就在于缓冲池中的部分空间分配给了其他对象,在上述的例子中是由于自适应哈希索引的关系∶
深入理解MySQL——LRU、Free和Flush 链表_第3张图片
node heap has 505 buffer(s)显示了自适应哈希索引占用了505个缓冲池中的页,可以看到在这里例子中,缓冲池中的页分配给了自适应哈希索引、free 链表与LRU链表中的页。

缓冲池中的页不仅需要被读取,还需要进行修改操作。修改的页肯定发生在 LRU链表中,当LRU链表中的页被修改后,则称该页为脏页(dirty page),即缓冲池中的页和磁盘上的页数据产生了不一致。这时数据库会通过 checkpoint 机制将脏页刷新回磁盘。而 flush 链表中的页即为脏页。需要注意的是,脏页既存在于LRU链表中,也存在于flush链表中。LRU链表用于管理缓冲池中页的可用性,flush 链表则用干管理将页刷新回磁盘,两者互不影响。图1-3显示了 free 链表、LRU链表、flush 链表之间的关系∶
图1-4 free链表、LRU链表、flush链表之间的关系

你可能感兴趣的:(深入理解MySQL,数据库,LRU,Flush链表,MySQL,InnoDB)