innodb_flush_neighbors 参数是InnoDB用来控制buffer pool刷脏页时是否把脏页邻近的其他脏页一起刷到磁盘,在传统的机械硬盘时代,打开这个参数能够减少磁盘寻道的开销,显著提升性能。
- 取值范围:0,1,2
- 默认值:5.7版本为1, 8.0版本为0
含义:
- 设置为0时,表示刷脏页时不刷其附近的脏页。
- 设置为1时,表示刷脏页时连带其附近毗连的脏页一起刷掉。
- 设置为2时,表示刷脏页时连带其附近区域的脏页一起刷掉。1与2的区别是2刷的区域更大一些。
如果MySQL服务器磁盘是传统的HDD存储设备,打开该参数,能够减少I/O磁盘寻道的开销,提高性能,而对于SSD设备,寻道时间的性能影响很小,关闭该参数,反而能够分散写操作,提高数据库性能。由于SSD设备的普及,MySQL 8.0 将该参数的默认值由1调整为0。
innodb_flush_neighbors参数源码分析:
源码版本:5.7.19
在源码中,innodb_flush_neighbors 参数对应的变量为srv_flush_neighbors,这是一个全局变量,默认值为1,如下:
ulong srv_flush_neighbors = 1;
整个代码中,用到变量 srv_flush_neighbors 的地方只有一个,那就是函数 buf_flush_try_neighbors(),该函数位于源码文件:storage/innobase/buf/buf0flu.cc
buf_flush_try_neighbors() 函数主要逻辑,如下:
static ulint buf_flush_try_neighbors(
const page_id_t& page_id,
buf_flush_t flush_type,
ulint n_flushed,
ulint n_to_flush)
{
if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN
|| srv_flush_neighbors == 0) {
// [low, high] 区间不包含邻近的页面
low = page_id.page_no();
high = page_id.page_no() + 1;
}else{
// [low, high] 区间包含邻近的页面
low = (page_id.page_no() / buf_flush_area) * buf_flush_area;
high = (page_id.page_no() / buf_flush_area + 1) * buf_flush_area;
if (srv_flush_neighbors == 1) {
...
// 根据 [low, high] 区间内的页是否可以刷盘,来进一步缩小 [low, high] 区间
}
}
...
// 根据 [low, high] 区间进行脏页刷盘
}
buf_flush_try_neighbors() 函数根据 [low, high] 区间来刷脏页。
- 当 srv_flush_neighbors 为 0时, [low, high] 只包含一个页面。
- 当 srv_flush_neighbors 为 1时, [low, high] 包含邻近的页面,页面数小于等于变量值buf_flush_area。
- 当 srv_flush_neighbors 为 2时, [low, high] 包含邻近的页面,页面数等于变量值buf_flush_area。