【MySQL】change buffer,buffer pool,redo log,bin log,undo log的作用

Change Buffer

当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。
在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
需要说明的是,虽然名字叫作 change buffer,实际上它是可以持久化的数据。也就是说,change buffer 在内存中有拷贝,也会被写入到磁盘上。
将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge。
除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。
显然,如果能够将更新操作先记录在 change buffer,减少读磁盘,语句的执行速度会得到明显的提升。
而且,数据读入内存是需要占用 buffer pool 的,所以这种方式还能够避免占用内存,提高内存利用率。

那么,什么条件下可以使用 change buffer 呢?
对于唯一索引来说,所有的更新操作都要先判断这个操作是否违反唯一性约束。
比如,要插入unique_key = 4这个记录,就要先判断现在表中是否已经存在 unique_key=4 的记录,而这必须要将数据页读入内存才能判断。如果都已经读入到内存了,那直接更新内存会更快,就没必要使用 change buffer 了。
因此,唯一索引的更新就不能使用 change buffer,实际上也只有普通索引可以使用。change buffer 用的是 buffer pool 里的内存,因此不能无限增大。change buffer 的大小,可以通过参数 innodb_change_buffer_max_size 来动态设置。这个参数设置为 50 的时候,表示 change buffer 的大小最多只能占用 buffer pool 的 50%。

因此,对于数据本身就存在于内存中的情况,那么普通和唯一索引的性能差距不大。
但是如果数据不存在内存中,那么唯一索引由于需要把数据从磁盘读取到内存中,无法使用change buffer,因此性能差了很多。

通过上面的分析,我们已经清楚了使用 change buffer 对更新过程的加速作用,也清楚了 change buffer 只限于用在普通索引的场景下,而不适用于唯一索引。

那么,现在有一个问题就是:
普通索引的所有场景,使用 change buffer 都可以起到加速作用吗?
因为 merge 的时候是真正进行数据更新的时刻,而 change buffer 的主要目的就是将记录的变更动作缓存下来,所以在一个数据页做 merge 之前,change buffer 记录的变更越多(也就是这个页面上要更新的次数越多),收益就越大。
因此,对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。 这种业务模型常见的就是账单类、日志类的系统。反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发 merge 过程。这样随机访问 IO 的次数不会减少,反而增加了 change buffer 的维护代价。所以,对于这种业务模式来说,change buffer 反而起到了副作用。

Buffer Pool

MySQL 中的 Buffer Pool 是为了优化磁盘 I/O 而引入的机制。MySQL 内部的页大小与操作系统的页大小可以不一致,MySQL 中的页大小通常是固定的,默认为16KB。

Buffer Pool 是一个内存区域,用于缓存从磁盘读取和维护的数据页。它的作用是减少磁盘 I/O 操作,提高数据库的性能和响应速度。当查询或修改数据时,MySQL 首先检查缓冲池中是否存在所需的数据页,如果存在,则可以直接从内存中读取或写入数据,从而避免了频繁的磁盘读写操作。

缓冲池的大小可以通过配置参数 innodb_buffer_pool_size 来设置。合理设置缓冲池的大小非常重要,过小的缓冲池可能导致频繁的磁盘 I/O,而过大的缓冲池可能浪费宝贵的内存资源。

为了更好地使用缓冲池,可以考虑以下几个方面:

根据系统的内存大小和数据库的访问模式设置合适的缓冲池大小。这需要综合考虑系统中其他进程和服务的内存需求。
监控缓冲池的使用情况,例如使用 show global status like ‘Innodb_buffer_pool%’ 命令来查看缓冲池的命中率、使用率等指标。可以根据监控结果来调整缓冲池大小。
确保表的索引足够优化,以最大程度地减少对磁盘的访问。
对于 Buffer Pool 中的数据如何保证与磁盘的数据一致性,InnoDB 引擎采用了写前日志(Write-Ahead Logging)的机制。在修改数据之前,InnoDB 会先将修改的数据写入日志文件(Redo Log),然后再将数据页更新到 Buffer Pool。这样即使系统崩溃或重启,可以通过日志的恢复操作来保证数据的一致性。

(WAL)写前日志是一种常见的数据库事务处理策略,旨在保证数据的持久性和一致性。在MySQL中,当进行数据修改操作时,InnoDB存储引擎首先会将修改操作写入日志文件(称为重做日志或者写前日志),然后再将相应的数据页更新到Buffer Pool中。这样做的好处是,即使在更新到磁盘之前发生了系统崩溃或断电等故障,数据库可以根据重做日志来恢复数据,保证数据的完整性和一致性。

换句话说,写前日志机制确保了数据的持久性,而Buffer Pool则用于提高查询性能,缓存经常访问的数据页,减少对磁盘的I/O操作。两者是协同工作的,保证了数据的安全性和数据库的高性能运行。

在正常情况下,MySQL 会根据一定的策略将 Buffer Pool 中的数据刷新到磁盘,以确保数据的持久性。
正常情况下,MySQL会定期将Buffer Pool中的脏页(已被修改但尚未写入磁盘的数据页)刷新到磁盘,以保证数据的持久性。刷新策略可以通过配置参数进行调整,如innodb_max_dirty_pages_pct和innodb_io_capacity等。

Redo Log

一言以蔽之:减少磁盘随机写,使用内存高速顺序写。提供奔溃数据恢复机制。

Redo Log日志为mysql提供了crash-safe的能力,也就是奔溃恢复能力。
我们知道,我们使用mysql的时候,其性能瓶颈在于随机的磁盘IO操作,因此如果能减少对磁盘IO的操作,那么能极大的提高性能。
我们再使用增删改操作的时候,其实就是一种随机IO操作,如果我们每次都把对应的操作数据从磁盘中读取出来然后修改再写入,那么性能可想而知的低。
所以,能不能有一种办法,我们能先把数据写到缓存(内存)中,然后再合适的时机再把这些数据写入到磁盘呢?
是有的,也就是我们所谓的Redo Log日志了。
当我们需要写入数据的时候,我们并不是把这些数据直接写入到磁盘,而是先写到redo log这种更快速的内存文件中,那么对性能的影响就会小很多了。
redo log中记录的是对mysql中数据块的操作。
当我们的mysql出现奔溃的时候,我们再次重启进行数据恢复的时候,就可以从redo log中把这些还没有写道磁盘中的数据给他进行写入,从而保证了数据一致性。

Bin Log

一言以蔽之:提供数据恢复,数据回滚,主从同步等功能。

Binlog(二进制日志)是MySQL中的一种日志文件,用于记录数据库的所有修改操作,例如插入、更新和删除。Binlog具有以下几个重要的作用和意义:

数据恢复与备份:Binlog可以用于数据的恢复与备份。通过将Binlog文件应用到MySQL实例中,可以将数据库还原到特定的时间点或特定的事务状态。这在数据丢失或数据库崩溃时非常有用。

主从复制:Binlog是MySQL主从复制的基础。在主从复制中,主数据库上的所有修改操作都会被记录到Binlog文件中,并通过网络传送给从数据库。从数据库根据Binlog文件的内容来执行相同的修改操作,从而保持与主数据库的数据一致性。

数据库同步与高可用性:Binlog可以用于实时地将变更操作传播到其他MySQL实例,从而实现数据库的同步和高可用性。通过将Binlog文件传输给其他MySQL实例,这些实例可以将变更操作应用到自己的数据库中,从而保持数据的一致性。

数据分析与查询回放:Binlog记录了数据库的所有修改操作,因此可以用于数据分析和查询回放。通过分析Binlog文件,可以了解到数据库的历史修改操作,进行性能分析、数据统计等工作。对于需要重放历史查询的场景,可以将Binlog文件应用到测试环境中,模拟执行查询操作。

在MySQL中,Bin Log是用于记录数据库的更改操作的二进制日志。以下是会写入Bin Log日志的操作:

DML语句(Data Manipulation Language):包括INSERT、UPDATE和DELETE语句,用于对表中的数据进行增、删、改操作。

DDL语句(Data Definition Language):包括CREATE、ALTER和DROP语句,用于创建、修改和删除数据库对象,如表、索引等。

DCL语句(Data Control Language):包括GRANT和REVOKE语句,用于授权和撤销权限。

数据更改函数和存储过程:如果函数或存储过程中包含了会修改数据的操作,那么执行这些函数或存储过程也会写入Bin Log日志。

写入Bin Log日志的目的是为了实现数据库的持久性和数据恢复。通过将更改操作记录到Bin Log中,可以在发生故障或数据丢失的情况下进行数据恢复和同步。此外,Bin Log日志还可以用于数据库复制、数据备份、数据迁移等场景。

Undo Log

一言以蔽之:MVCC多版本并发控制的视图所能看到的数据依赖于此。

Undo log(回滚日志)是MySQL InnoDB存储引擎中的一部分,用于实现事务的原子性和一致性。它的作用是记录事务操作的反向操作,以便在事务回滚或系统崩溃时,可以恢复到事务开始前的状态。

当一个事务开始时,InnoDB会为该事务创建一个undo log。在事务执行期间,如果发生了数据修改(例如插入、更新、删除),则会在undo log中记录相应的反向操作,以便在回滚时可以撤销这些修改。

具体而言,对于插入操作,undo log记录了插入的数据和哪个位置需要删除该数据;对于更新和删除操作,undo log记录了被修改或删除的数据和如何还原到原有状态的操作。

当一个事务需要回滚时,InnoDB会根据对应的undo log中的反向操作,将之前的数据修改撤销,恢复到事务开始前的状态。这种能力是事务的基本特性之一,保证了事务的原子性和一致性。

对于MySQL的性能影响来说,undo log会占用一定的存储空间。每个事务的undo log都需要先写入磁盘,这可能引起一定的IO开销。同时,在事务并发执行时,undo log的管理和读写也会引起一些额外的开销,因此在高并发场景下,需要合理设置undo log的大小和管理策略,以保证系统性能的平衡。

Undo log在MySQL InnoDB存储引擎中与多版本并发控制(MVCC)密切相关,并且在MVCC中起到重要作用。MVCC是一种并发控制机制,用于实现高并发环境下的事务隔离性。

MVCC通过为每个事务分配唯一的事务ID(Transaction ID)和版本号来管理事务的并发访问。当一个事务开始时,会记录当前数据库中的快照版本。随着事务的进行,其他事务可以继续对数据库进行读操作,读取快照版本的数据,而不会受到当前事务所做的修改的影响。

这就引入了undo log的作用。在MVCC中,当一个事务正在对数据进行修改时,为了保证其他事务能够读取到一致的数据,InnoDB会将修改前的数据拷贝一份到undo log中,并在undo log中记录该操作的版本号。

当其他事务读取数据时,如果该数据被正在进行修改的事务修改了,InnoDB会根据事务的版本号和undo log中的信息,通过回滚操作将该数据还原到修改前的状态,然后读取这个被还原的数据,保证了读取的一致性。

因此,undo log在MVCC中的作用是提供了用于还原数据的历史版本,以确保事务读取的数据是一致的。它用于实现数据的回滚和回滚段的管理,为MVCC提供了必要的支持。

需要注意的是,MVCC不仅仅依赖于undo log,还与其他机制(如读视图、回滚段等)紧密结合,以实现事务的隔离性和并发控制。undo log作为其中的一部分,发挥了关键的作用。

这几个日志的协作流程

当根据修改请求对应的数据是否在内存中,分别对这些日志进行操作的执行流程如下:

Change Buffer:首先,修改操作会在内存的Change Buffer中进行记录。Change Buffer是MySQL的一种机制,用于延迟对磁盘上对应页的实际修改,以提高性能。修改操作在Change Buffer中被记录下来,而不是立即写入磁盘上的对应页。

Buffer Pool:数据在内存中的主要存储位置是Buffer Pool(也称为页缓存)。当修改操作需要读取数据页时,MySQL会先检查Buffer Pool中是否存在要修改的页。如果存在,就直接在Buffer Pool中进行修改操作。如果要修改的页不在Buffer Pool中,那么下次查询出来这条数据的时候,我们就会把他加载到Buffer Pool并且使用Change Buffer里面的修改操作来对他进行操作。

Undo Log:在修改操作执行过程中,MySQL会将对原始数据的修改操作记录到Undo Log中。Undo Log用于回滚事务或者恢复数据到之前的版本。通过记录修改前的数据,MySQL可以在需要时撤销或回滚修改操作。

Redo Log:同时,修改操作的日志也会写入到Redo Log中。Redo Log是用于崩溃恢复的重要日志。它记录了所有的修改操作,以保证即使在异常情况下数据的持久性。

Bin Log:最后,修改操作还会记录到Bin Log(二进制日志)中。Bin Log是用于复制和恢复的日志。通过记录修改操作,可以在主从服务器之间同步数据,并且可以用于在灾难恢复时恢复数据。
注意,最后写Bin Log日志以及Redo Log日志的过程涉及到两阶段提交。

也就是不论是否使用到Change Buffer,只要我们做了修改操作,我们就会写入数据到redo log中

猜你喜欢

转载自blog.csdn.net/Zhangsama1/article/details/131811216