MySQL作为一个数据存储系统,是具有缓冲池(buffer pool)这么一个机制的,这是为了避免每次查询数据都进行磁盘IO,可以提高数据访问的效率。
缓冲池是一个很大的内存区域,里面放着各种类型的页。那么InnoDB引擎是这么管理这么大的内存区域的呢?
通常来说,数据库中的缓冲池是通过LRU(Latest Recent Used,,最近最少使用)算法来进行管理的。这是一个类似Redis的LFU(less frequently used)淘汰策略算法,即最频繁使用的页放在LRU列表的最前端,反之,最少使用的页放在LRU列表的最末端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾部的页。
在InnoDB引擎中,缓冲池中页的大小默认为16KB,也是使用LRU算法对缓冲池进行管理,不过InnoDB引擎在LRU算法原有的基础上做了一些优化。你问我为啥要对LRU算法进行改动,直接将最新读取的页放入到LRU列表的最前端不合理吗?
合理,但是在特定情况下不太合理,因为如果不改动算法直接将最新读取到的页放入到LRU列表的的最前端,那么会有一些特定的SQL操作可能会使缓冲池中一些还有用处的页被算法从列表中淘汰,这会大大影响缓冲池的效率。常见的这类操作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页通常来说又仅只是在这次查询操作中需要用到,并不是什么活跃的热点数据。如果在进行这种操作时,大量的页被放入LRU列表的首部,那么根据原有算法的机制可能就会把一些还有用处的热点数据页从LRU列表中淘汰,那下一次需要读取该页时,InnoDB存储引擎又要再次访问磁盘,这同样也会影响效率。
那么InnoDB究竟对LRU算法做了那些改动呢?
在InnoDB的存储引擎中,LRU列表里加入了midpoint位置。新读取到的页,虽然是最新访问的数据,但是并不直接放入LRU列表的最前端,而是放入到LRU列表的midpoint位置。
这个算法在InnoDB存储引擎中叫做midpoint insertion strategy。在默认配置下,该位置在LRU列表长度的5/8处。
midpoint的位置可通过修改配置参数innodb_old_blocks_pct来控制,这样就解决了特定数据访问操作导致算法误判把热点数据淘汰了,从而影响缓冲池工作效率的问题。(是不是很妙)
以上内容主要来自《MySQL技术内幕》和我的一些浅显的理解。(厚脸皮发个原创),这本书确实不戳(不是广告),感兴趣的小伙伴可以去淘宝的新华书店购买。