(1)概述:查询语句导致的大量的脏页刷回磁盘文件中
    平时在数据库执行的更新语句,实际上都是从磁盘上加载数据页到数据库内存的缓存页里,接着就直接更新内存里的缓存页,同时还更新对应的redo log写入一个buffer 中,既然更新了Buffer Pool里的缓存页,缓存页就会变成脏页,之所以说它是脏页就是因为缓存页里的数据目前跟磁盘文件里的数据页的数据是不一样的,所以此时叫缓存页是脏页。
    71.jpg 72.jpg
    既然是脏页,那么就必然的有一个合适的时机把脏页给刷入磁盘文件里去,之前分析过脏页刷入磁盘的机制,他是维护了一个lru链表,通过lru链表知道哪些缓存页是最近经常被使用的,后续如果加载磁盘文件的数据页到buffer pool里去,但是此时没有空闲的缓存页了,此时就必须把部分脏缓存刷入磁盘里去,此时会根据lru链表找出最近最少使用被访问的缓存页刷入磁盘。
    万一执行的是查询语句,需要查询大量的数据到缓存页里去,此时可能导致内存里大量的脏页需要淘汰出去刷入磁盘,才能腾出足够的内存空间来执行这条查询语句。
    在这种情况下,可能你会发现突然线上数据库执行某个查询语句一下子性能出现抖动,平时只要几十毫秒的查询语句,这次一下几秒都有可能,毕竟等待大量脏页刷盘,然后语句才能执行。需要buffer pool腾出大量的空间供查询出来的大量数据页加载进入buffer pool里,腾出空间肯定需要大量内存空间刷盘。

    (2)另外还有一种脏页刷盘的契机:redo log 日志文件覆盖
    redo log buffer里的redo log本身也是会随着各种条件刷入磁盘上的文件,比如redo log buffer 里的数据超过容量的一定比例,或者事务提交的时候,都会强制buffer里的redo log 刷入磁盘上的日志文件,然后我们也知道,磁盘上是有多个日志文件的,他会依次不停的写,如果所有日志文件都写满了,此时会重新回到第一个日志文件再次写入,这些日志是不停的循环写入的,所以其实在日志文件被写满的情况下,也会触发一次脏页的刷新。
    为什么呢?因为假设 第一个日志文件的一些redo log 对应的内存里的缓存页 的数据都没被刷新到磁盘上的数据页里去,一旦第一个日志文件里的这部分redo log覆盖写了别的日志,此时万一数据库崩溃,之前更新过的数据就彻底丢失了。
    73.jpg
    redo log日志用来做宕机恢复的,如果宕机了需要根据redo log日志进行恢复,但是如果日志文件写满了,开始覆盖写入第一个日志文件,首次覆盖的这个第一个日志文件的一部分redo log日志 对应的buffer pool缓存里的 这个redo log记录的脏页还没刷入磁盘,此刻宕机了,那这个buffer pool里的脏页通过什么来恢复然后刷入磁盘?
    这个redo log日志被覆盖了,所以在进行覆盖时要先 判断被覆盖的这个redo log日志文件的这部分 对应的buffer pool的脏页 是否已经刷入磁盘文件了,如果刷入了即使宕机,也已经刷入磁盘文件,不会出现数据丢失。如果没有刷入磁盘,那在覆盖这部分redo log日志之前先把脏页刷入磁盘,然后再进行覆盖。
    所以一旦所有日志文件写满,此时重新从第一个日志文件开始写入的时候,MySQL会判断一下,是否出现如果第一个日志文件里的一些redo log对应之前更新过的缓存页,迄今为止都没刷入磁盘的,那么此时必然是把那些马上要被覆盖的redo log更新的缓存页都刷入磁盘。

    尤其是这一种刷脏页的情况下,因为redo log所有日志文件都写满了,此时会导致数据库直接hang死,无法处理任何更新请求,因为执行任何一个更新请求都必须写redo log,此时需要刷新一些脏页到磁盘,然后才能继续执更新语句,把更新语句的redo log从第一个日志文件开始覆盖写。所以假设执行大量的更新语句,可能突然线上数据库很多更新语句短时间内性能都抖动了,平时很多更新语句就几毫秒执行好了,这次要等待1秒执行完毕。

    因此遇到这种情况,必须等待第一个日志文件里部分redo log对应的脏页都刷入磁盘了,才能继续执行更新语句,磁盘必然会导致更新语句的性能很差。

    (3)总结
    综上所述,导致线程数据库的查询和更新语句出现性能抖动,其实很可能是上述两种情况导致的执行语句时大量刷脏缓存页刷入磁盘,等待刷完磁盘才能继续执行导致的。

    这篇看了几遍才看懂,把之前的知识有回顾了一下,才明白redo log日志被覆盖需要刷盘的原因,首先redo log日志文件写满后开始覆盖第一个redo log 日志文件,redo log日志文件作用是宕机恢复已提交事务的数据,假设redo log日志文件的一部分日志被覆盖了,那这部分日志对应的buffer pool里的脏页还没刷入磁盘,此刻宕机,那怎么办?怎么恢复?这是恢复不了的,所以被覆盖的这部分日志被覆盖之前要先检查这部分redo log对应的buffer pool里的缓存页是否刷入磁盘文件中了,刷入磁盘了,即使宕机,因为落盘了也不会影响,如果没刷入磁盘,这时要先刷入磁盘,不然宕机没法恢复,因为redo log要被覆盖了。所以如果不巧的脏页没刷入磁盘,那还要刷脏页进磁盘,然后覆盖,这样明显损耗了性能。