Buffer Pool之LRU算法
buffer pool是主内存中,InnoDB引擎用来缓存表和索引数据的一块区域。buffer pool会存储高频访问的数据,这加速了访问。
在专用数据库服务器上,80%的无力内存都会分配给buffer pool。
为了提高读取大量数据时的效率,buffer pool被分成多个page,每个page可以存储多条记录。为了提高缓存管理效率,buffer
pool使用了最近最少使用(LRU)算法,不常访问的数据会被从缓存中淘汰。
怎样利用buffer pool来使常用数据都在内存中,是MySQL调优的一个重要方面。
Buffer Pool 的 LRU算法 #
buffer使用LRU算法,以链表的形式来管理内存。当需要向buffer buffer中添加一个新page时,最少使用的page被淘汰,向链表
的中间插入一个新page。这种中间插入的的策略将联调分成了两部分:

- 链表头部,包含最近使用的page,称为young区域。
- 链表尾部,包含最少使用的page,称为old区域。

LRU算法保证最常使用的page在young区域。old区域的数据是最不经常使用的,将被淘汰的page就来自这里。
算法的默认操作如下:
- old区域占比3/8。
- 分界线左边是young区域的尾部,右边是old区域的头部。
- 当InnoDB读取一个page到buffer pool中时,会将其插入到old区域的头部。读取page,可能是因为用户操作,比如一个SQL查询,
也可能是因为InnoDB的预读操作。
- 读取old区域中的page会使其变为yong,并移动到young区域的头部。如果这个page是因为用户操作被读的,第一次访问这个page就
会使其变young。如果是因为预读操作,那可能直到被淘汰都不会别访问。
- 在数据库操作中,未被问过的page会“变老”,并向链表尾部移动。在某个page被移动到young的头部时,young区域和old区域的page
都会变老。在新的page被添加到old区域头部时,old区域中的其它page会变老。最终,一个未访问的page会移动到old区域尾部,并被淘汰。
一般情况下,查询访问的page会立即被移动到young区域的头部,这意味着它们会在buffer pool中停留的时间更长。如果是全表扫描(例如
mysqldump操作或没有where语句的SELECT操作),会读取大量数据到buffer pool中,并淘汰等量的旧数据,即使新数据不会被再次使用。
类似地,后台预读线程读取的数据页可能只被读取一次就移动到young区域头部。这些场景会迫使经常访问的page向old区域移动,最终被淘汰。
要想了解这种场景下的优化信息,可以查看15.8.3.3 "Making the Buffer Pool Scan Resistant",和 15.8.3.4 "Configuring InnoDB Buffer Pool Prefetching"

InnoDB标准监控会在BUFFER POOL AND MEMORY部分输出buffer pool LRU算法相关的字段。欲知详情,欢迎查看下一章。