【1】介绍
InnoDB维护一个称为缓冲池的存储区域, 用于在内存中缓存数据和索引。利用它将经常访问的数据保存在内存中,是 MySQL 调优的一个重要方面。
【2】缓冲池预取(Read-Ahead)
【2-1】含义
预读是当发起一个 I/O 请求时候,它异步地预取缓冲池中的多个页面。也就是认为你接下来很有可能会查询当前请求后面的数据,所以预先把接下来的部分数据页读取出来。
InnoDB 以 64 个 page 为一个 extent。以按 page 或 extent 为预读单位分为两种预算算法 线性预读 和 随机预读。
【2-2】预读算法
线性预读(Linear read-ahead)
线性预读 以 extent 作为预定范围单位,它根据缓冲池中按顺序访问的页面来预测可能很快需要哪些页面。
触发时机由参数 innodb_read_ahead_threshold 控制,默认为 56 。含义是当一个 extent 中被顺序读取的页个数大于等于这个值,就会把下一个 extent 读取到 buffer pool 中,这个操作是伊布执行的。
show variables like 'innodb_read_ahead_threshold';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| innodb_read_ahead_threshold | 56 |
+-----------------------------+-------+
若该值没有被设置,InnoDB 只会在读取当前 extent 的最后一页时计算是否对整个next extent 发出异步预取请求。
所以可以根据你的数据特点合理的增加过减小这个值,从来享受到预读带来的性能提升。
随机预读 (Random read-ahead )
随机预读 以 页 作为预定范围单位,也就是一个 extent 中的 64个页为预读范围。它根据缓冲池中已有的页面来预测何时可能很快需要页面,而不管这些页面的读取顺序如何。
触发由参数 innodb_random_read_ahead 控制,默认是关闭的,开启需设置为 ON。
由于随机预读相对复杂性,同时在性能也存在不稳定性,在5.5中已经将这种预读方式废弃。
涉及到的参数如下:
- Innodb_buffer_pool_read_ahead - 预读后台线程读入 InnoDB 缓冲池的页数。
- Innodb_buffer_pool_read_ahead_evicted - 由预读后台线程读入 InnoDB 缓冲池的页面数,这些页面随后在未被查询访问的情况下被清除。
- Innodb_buffer_pool_read_ahead_rnd - InnoDB 启动的“随机”预读次数。
【3】总结
预读是后台线程异步完成的,由参数 innodb_read_io_threads 控制数量。默认 4 个。
show variables like 'innodb_read_io_threads';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_read_io_threads | 4 |
+------------------------+-------+
可以使用 SHOW ENGINE INNODB STATUS;看到实时的信息。可以看到类似的信息:
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 5494538240; in additional pool allocated 0
Total memory allocated by read views 1832
Internal hash tables (constant factor + variable factor)
Adaptive hash index 234507568 (84999368 + 149508200)
Page hash 2657176 (buffer pool 0 only)
Dictionary cache 33247833 (21251248 + 11996585)
File system 1092256 (812272 + 279984)
Lock system 13289536 (13281976 + 7560)
Recovery system 0 (0 + 0)
Dictionary memory allocated 11996585
Buffer pool size 327678
Buffer pool size, bytes 5368676352
Free buffers 2042
Database pages 316511
Old database pages 79091
Modified db pages 6328
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 130098310, not young 30432004147
7.29 youngs/s, 30.49 non-youngs/s
Pages read 562355000, created 7100860, written 152881342
16.18 reads/s, 0.11 creates/s, 28.29 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
// Pages read ahead:表示每秒读入的pages
// evicted without access:表示每秒读出的pages
// Random read ahead 0.00/s 随机读通常是0,因为一般不开启。
LRU len: 316511, unzip_LRU len: 0
I/O sum[4754]:cur[52], unzip sum[0]:cur[0]
InnoDB 提供一些信息直观的显示预读效果,可使用语句 show global status like ‘%read_ahead%’;
show global status like '%read_ahead%';
+---------------------------------------+-----------+
| Variable_name | Value |
+---------------------------------------+-----------+
| Innodb_buffer_pool_read_ahead | 122663562 |
| Innodb_buffer_pool_read_ahead_evicted | 0 |
| Innodb_buffer_pool_read_ahead_rnd | 0 |
+---------------------------------------+-----------+
Innodb_buffer_pool_read_ahead 通过预读(后台线程)读入innodb buffer pool中数据页数。
Innodb_buffer_pool_read_ahead_evicted 过预读来的数据页没有被查询访问就被清理的pages,也就是无效预读的页数。
Innodb_buffer_pool_read_ahead_rnd 启动的“随机”预读次数,通常不启用所以是 0.