[InnoDB 学习1-2] 内存

 

内存

缓冲池

InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理

在数据库系统中,由于CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。

原理:

缓冲池就是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。

读:在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中。下次再读到相同的页时,首先判断该页是否在缓冲池中。若在缓存池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。

写:对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定频率刷新到磁盘上。(注:页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为Checkpoint的机制刷新回磁盘。这是为了提高数据库的整体性能。)

缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)、数据字典信息(data dictionary)等。

新版本允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。这样做的好处是减少数据库内部的资源竞争,增加数据库的并发处理能力。

LRU List、Free List、Flush List

LRU List

缓冲池是一个很大的内存区域,其中存放各种类型的页。那么InnoDB存储引擎是怎么对这么大的内存区域进行管理的呢?

通常,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的。即最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。

不同的是InnoDB存储引擎对传统的LRU算法做了一些优化。在LRU列表中还加入了midpoint位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到LRU列表的首部,而是放入到LRU列表的midpoint位置。默认配置下,该位置在LRU列表长度的5/8(37%)处。

mysql> show variables like 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+

缓冲池中页的大小默认为16KB

新版本支持压缩页,即将原本16KB的页压缩为1KB、2KB、4KB、8KB。对于非16KB的页,是通过unzip_LRU列表管理的。

通过伙伴算法进行内存的分配。先拆分unzip_LRU列表,再拆分LRU列表。

为什么不采用朴素的LRU算法,直接将读取的页放入到LRU列表的首部呢?

因为若直接将读取到的页放入到LRU的首部,有些操作需要访问表中的许多页,甚至全部页,而这些页通常仅在这次查询操作中需要,并不是活跃的热点数据。如果放入LRU列表首部,很可能热点数据被从LRU列表中移除,而下一次需要时,需要再次访问磁盘。

解决:

InnoDB存储引擎引入了另一个参数进一步管理LRU列表,用于表示页读取到mid位置后需要等待多久才会被加入到LRU列表的热端。

当执行一些SQL操作时,要尽可能是LRU列表中的热点数据不被刷出。

mysql> show variables like 'innodb_old_blocks_time';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000  |
+------------------------+-------+

查看缓冲池运行状态:

mysql> select pool_id, hit_rate, pages_made_young, pages_not_made_young from information_schema.innodb_buffer_pool_stats;

pages_made_young显示LRU列表中页移动到前端的次数。 hit_rate值不应该小于95%,否则,需要检查是否是由于全表扫描引起的LRU列表被污染的问题。

Free List

Free列表用处:

LRU列表用来管理已经读取的页,但当数据库刚启动时,LRU列表是空的,即没有任何的页。这时页都存放在Free列表中。

当需要从缓冲池中分页时,首先从Free列表中查找是否可用的空闲页,若有则将该页从Free列表中删除,放入到LRU列表中。

根据LRU算法,淘汰LRU列表末尾的页,将该内存空间分配给新的页。

Flush List

Flush列表作用:

在LRU列表中的页被修改后,称该页为脏页(dirty page),即缓冲池中的页和数据页产生了不一致。

这时数据库会通过CHECKPOINT机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。

注:脏页即存在于LRU列表,也存在于Flush列表中。