MySQL InnoDB缓存池(Buffer Pool)

MySQL缓存池是内存中的一块区域,用于缓存表和索引数据,以便能直接从内存中处理常用数据。在专用服务器上,InnoDB缓存池对物理内存的占用最高可达80%。

InnoDB缓存池监视器

SHOW ENGINE INNODB STATUS

缓存池列表(Buffer Pool List)

InnoDB使用LRU算法(最近最少使用)的变种,将缓冲池作为列表进行管理。最近访问过的页放在“头部”,旧页会被推到“尾部”,最终被驱逐出缓存。尾部默认占用缓冲池3/8内存(可调整范围5~95,默认为:innodb_old_blocks_pct=37)。

不带WHERE条件的SELECT语句和mysqldump操作都会将大量数据带入缓冲池,相应数量的旧数据同时会被移出。

InnoDB对缓存池的管理并非严格意义上的LRU算法,以此,来防止预读和全表扫描带出的非热点数据留在缓存中。InnoDB将新读取的块插入到LRU列表的中间,所有新读取的页面默认放在LRU列表“尾部”区域。

当某个页面的数据被访问时,页面将被移动到列表的“头部”区域,而未被访问到的页面会被快速“老化”驱逐出缓存。InnoDB允许对LRU列表插入点进行控制。

若有很多数据被连续访问几次后就不再被触及,可以调整页面第一次被访问后的时间窗口(默认:innodb_old_blocks_time=1000),窗口期间数据不会被移动到LRU列表的“头部“区域。

写缓冲区(Change Buffer/ibuf btree)

当二级索引页不在缓存池中,对二级索引所做的操作将会被缓存于此,以此,减少二级索引的随机I/O,并达到合并操作的效果。

与聚簇索引不同,二级索引通常是不唯一的,且插入二级索引的顺序相对随机。删除和更新都有可能会影响到相邻的二级索引页。当受影响的页面被其他操作读入缓存池时,就需要合并缓存的更改,避免了从磁盘读取二级索引页到缓存池,而产生大量的随机访问I/O.

控制此缓存中的数据类型,使用innodb_change_buffering参数,默认值为all,可选范围(none、inserts、deletes、changes、purges、all)。此缓存的大小默认为innodb_change_buffer_max_size=25,最大允许50。

日志缓冲区( Log Buffer)

日志缓冲区存放日志数据的内存区域。日志缓冲区默认innodb_log_buffer_size=16MB。日志缓冲区的内容会定期刷新到磁盘。大型日志缓冲区确保大型事务能够运行,无需在事务提交之前将redo log(重做日志)数据写入磁盘。因此,如果有更新、插入或删除多行的事务,应增加日志缓冲区的大小以节省磁盘I/O。

innodb_flush_log_at_trx_commit控制日志如何写入缓冲区,默认为1,取值范围:0(每秒刷盘)、1(在每次事务提交时写入日志并刷新到磁盘)、2(每次事务提交后写入日志,且每秒刷一次盘)。

innodb_flush_log_at_timeout控制日志刷新频率,默认为1,最大值为2700,单位为秒。

缓存池配置原则

理想情况下缓冲池尽可能的大,以便一次从磁盘中读出更多数据到内存,为后续查询使用。

在足够内存的64位系统上,可以将缓冲池拆分为多个部分,以最大限度地减少并发操作之间的竞争。