Mysql-(五)-mysql的数据加载以及BufferPool对于数据的维护


背景:

通过前四章的学习,对于mysql有了初步的认识,我们在此基础上,在较之前稍微更细致的了解下mysql的执行流程。此外需要说明的是,相关学习资料借鉴于中华石杉老师,感谢共享。


引言

在这里插入图片描述
     ~~~~     对于mysql存放的数据,逻辑概念上我们称之为表,在磁盘等物理层面而言是按数据页形式进行存放的,当其加载到mysql中我们称之为缓冲页

     ~~~~     每个缓冲页都有对应的一份描述信息,存放了缓存页的一些元数据相关信息,通过描述信息可以快速定位到缓存页,呢么最气开始描述信息指向的缓存页都是没数据的,这一步会先将磁盘数据进行加载(见上图)。

     ~~~~     后续相关内容建立在存储引擎为innodb下;


一)数据加载至BufferPool

     ~~~~     从磁盘加载一个数据页到mysql中存在很多不简单的问题,比如它是如何保证同一份数据页不会在mysql中重复加载?以及mysql如何是如何得到当前数据页是否被加载的呢?

答案是缓存

     ~~~~     对于已经加载到musql的数据页,mysql将对其进行缓存,这样一方面当我们需要使用到数据页信息的时候,则可以通过缓存信息快速定位到mysql中对应的缓存页 ,mysql中的innodb大致就是以此思路。

当一条语句要执行时,

  1. 通过sql语句中的数据库名表名可以知道我们需要加载的数据页处于哪个表空间。
  2. 根据sql语句本身也可以通过一致性算法得到数据页
  3. 进而根据数据页号,可以从数据页缓存中(本质为一个哈希表)得到对应缓存页地址。
  4. 通过缓存页地址我们直接就可以到innoDB的缓冲池中定位到缓存页

在这里插入图片描述

通过以上几个步骤,我们将磁盘中的数据页加载到innodb 中的buffer pool 了。

呢么,mysql是如何确定哪些缓存页是空闲的呢?

倘若此时想找一个空闲的缓存页去存放从磁盘读取的数据页,该怎么做呢? 毕竟加载过数据的缓存页跟没加载过数据的缓存页混在一起,还是蛮麻烦的事情。

mysql 引入了free链表这样的数据结构,将呢么还没被使用的缓存页的描述信息用双向虚幻链表进行组合,需要用到时就卸一个节点出来存放数据。

呢么,目前流程大致如下:
在这里插入图片描述

     ~~~~     此时数据页被加载到缓存页,当缓存页具备了数据后,相关的变动信息也需要写回到描述信息中。同时,因为缓存页已经有了数据,描述信息节点需要从free链表中脱离,转移到lru链表中,过程如下。

在这里插入图片描述

     ~~~~     LRU链表的目的就是为让被访问的缓存页能够尽量排到靠前的位置,呢么此时如果内存不足,需要淘汰掉一些缓存页时,就可以从lru链表尾部,最终从尾结点开始进行删除。

通过上述流程,将sql所需的数据将在到Buffer poll中了,接下来到后续的innoDB中执行更新操作。


二)BufferPool中的数据如何处理

     ~~~~      此时待处理数据已从磁盘加载到缓冲池中,下一步当然就是执行更新操作了。先对需要更新的行数据加锁、原始数据写一份到redo log 中便于可能的回滚操作、执行update操作,此时缓存页的数据就被更新了。
     ~~~~      且此时此刻,缓存页的数据和磁盘中的数据就不一致了,这样的缓存页我们称之为脏页,过程如下。

在这里插入图片描述
     ~~~~      接下来就是如何进行刷脏,呢么首先我们该怎么知道哪些缓存页是脏页呢?

如果能把脏页和空闲的缓存页分离出来,我们就可以把相关的脏页数据及时写到磁盘中,随后进行脏页释放。这里的innoDB设计的方法类型与free链表,并设计了一个flush链表,存放的是在缓冲池中被更新过数据的缓存页。这些缓存页的描述信息都会被添加到flush链表中。其中需要说明的是free链表、lru链表、flush链表都是双向循环链表,且节点都为缓存页的描述信息,其中flush链表的节点同时也在lru链表中。

在这里插入图片描述

在这里插入图片描述

2.1)缓冲池内存不足触发脏页刷盘

     ~~~~      若后续的sql需要把磁盘中的数据加载中缓存页中,碰到内存告罄,则需要先清理下内中的缓存页了。

     ~~~~      通过之前的lru链表,可以找到lru链表中的尾节点,相比而言访问量是最低的,呢么当内存不够用的时候,自然要被优先清理掉。因为flush链表的节点也在lru链表中,此时在缓存页清理的时候需要做一项简单的判断。

  • 缓存页既在lru表尾的节点同时也在flush链表中,第一步事情是需要先进行刷脏,随后释放掉缓存页的内存,保证事务的相关修改可以正确同步至磁盘中。
  • 缓存页不在flush链表中,则直接执行简单的释放缓存页内存即可,然后将这些释放完内存缓存页的描述信息,重新添加到free链表中

在这里插入图片描述


2.2)mysql预读机制带来的问题

     ~~~~      mysql预读机制对上述流程是有较大的干扰。
当一个数据页被加载到缓冲池中,它可能会顺带把其他无关紧要的数据页也加载到缓冲池中,这些顺带加载到内存的数据页,往往被访问的概率会低于期望数据。但是由于lru链表的特别,新加入的总会有限被排在lru的链表头。导致这些顺带进来的、访问频率比较低的缓存页排在比较靠前的位置,也会消耗free链表。LRU链表反而会把呢些本来访问频率较高、但是此时被排挤到lru链表尾的缓存页的数据进行刷盘清理。

优化后的lru链表主要引入了冷热数据分离的思想解决了mysql预读机制带来的问题。

将Lru链表分为热数据区与冷数据区,从磁盘加载数据到LRU链表的时,首先会将加载到的缓存页直接放到冷数据的表头,如果1000MS(配置)后冷数据又被访问了,将变更为热数据,此时将从冷数据区的链表给移动到热数据区链表的表头,通过该步骤将热、冷分离。

流程见下:
在这里插入图片描述
     ~~~~     同样,为了避免缓冲池内存不够,实际上后台会有一个线程挂在定时任务上,不断从lru链表尾部将缓存页刷回至磁盘中并同时释放缓存页。

为了维护【热】数据的访问,LRU的访问做了很多优化,所以当一次错误的全表查询又推动相关缓存页进入热LRU,是真的很不应该的一件事情。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值