【数据库日志】undo log、redo log和bin log作用及原理
执行一条查询SQL发生了如下流程:
那么,执行一条Update语句经历了什么呢,流程和查询类似如下:
- 客户端玉连接器建立连接,连接器判断用户身份
- 因为是一条update所以不需要经过缓存,但是1表中有更新语句,需要把整个表的缓存进行删除(8.0版本移除了缓存)
- 解析器会通过词法分析识别出update、表名等构建出语法树和语法分析判断sql是否出现语法问题
- 由于处理器会判断表中字段或者表是否存在
- 优化器会确定执行计划,内部进行部分优化是否走索引等等
- 执行器负责具体执行,找到这一行数据进行执行
但是,更新语句会涉及到undo log(回滚日志)、redo log(重做日志)、bin log(归档日志)这三种日志:
- undo log:是在innodb存储引擎层生成的日志,实现了事务的原子性,主要是用于事务的回滚和MVCC
- redo log:是在innoddb存储引擎层生成的日志,实现了事务的持久性,主要是用于掉电等等故障恢复
- bin log:是在server层生成的日志,主要是用于数据备份和主从复制
为什么需要Buffer Pool
Mysql中的数据都是存储在磁盘当中的,那么我们更新一条数据的时候,为了提升查询速度会将这条数据放在缓存起来。为此,innodb存储引擎设计了一个缓冲池,来提升数据库的读写性能。
- 当读取数据的时候,如果数据存储在Buffer Pool中客户端就会直接读取Buffer Pool中的数据,否则再去磁盘中进行读取
- 当修改数据的时候,如果数据存在Buffer Pool中,那么直接修i该Buffer Pool中的数据也,然后将其页设置为脏页,为了减少磁盘IO不会立即将脏页写入到磁盘当中,后续由后台线程选择一个合适的时机将脏页写入到磁盘当中
Buffer Pool中缓存的是什么
InnoDB会把存储的数据换分为若干页,以页作为磁盘和内存进行交互的基本单位,,一个页默认的大小是166KB
在Mysql启动的时候,InnoDB会为Buffer Pool申请一片连续的内存空间,然后按照默认的16KB的大小划分出一个一个的页,Buffer Pool中的页就叫做缓存页。此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到Buffer Pool中
所以,Mysql启动的时候,就会观察到使用的虚拟内存空间很大,而使用到的物理内存空间却是很小,这是因为只有这些虚拟内存被访问后,操系统才会触发缺页中断,申请物理内存,接着虚拟内存和物理内存建立映射关系
Buffer Pool除了缓存索引页和数据页,还包括Undo页、插入缓存、锁信息等
undo log作用
实现事务的回滚,保证事务的原子性:如执行insert就会在日志中记录一条delete语句
实现MVCC:MVCC就是通过ReadView+undo log实现的。undo log会记录每一条记录保存多份历史数据,mysql在执行快照读(普通的select),会根据事务的Read View里的信息,顺着undo log版本链找到满足其可见性的记录
redo log作用
Buffer Pool是用来提升读写效率的,但是问题来了,Buffer Pool是基于内存的,而内存是不可靠的,万一遇到断电重启,内存中没有落盘的数据就会丢失。
为了防止断电导致的数据丢失,有一条数据需要更新的时候,InnoDB引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以redo log的形式记录下来,这个时候就算更新完成了
后续,InnoDb引擎就会在适当的啥时候,由后台线程将缓存在Buffer Pool的脏页数据刷新到磁盘中,这个就是WAL技术
WAL技术指的就是,Mysql的写操作并不是立刻写到磁盘中,而是先写日志,在合适的时间在写到磁盘上
redo log是物理日志,记录了某个数据页做了什么修改,比如对XX表空间的XX数据页XXX偏移量的地方做了XX的更新,每当执行一个事务就会产生这样的一条或者多条的物理日志
在事务提交的时候,只要先将redo log持久化到磁盘中即可,可以不需要等到将缓存在Buffer Pool里的脏页数据持久化到磁盘
当系统崩溃的时候,虽然脏页数据没有持久化,但是redo log已经持久化了,Mysql重启后,可以根据redo log的内容,将所有数据恢复到最新状态
redo log 要写到磁盘,数据也要写到磁盘,为什么要多此一举呢
保证数据的持久性
- 数据库系统在运行过程中,为了提高性能,数据的修改通常先在内存的缓冲池中进行,而不是立即写入磁盘。redo log 记录了对数据进行修改的操作记录,当数据库发生故障(如服务器崩溃、突然断电等)时,在数据库恢复阶段,系统可以根据 redo log 中的记录,将未写入磁盘的数据修改操作重新执行一遍,从而保证数据的持久性和一致性,确保已提交的事务不会丢失。
提升数据库的性能
- redo log的方式是追加操作,所以磁盘操作是顺序IO,而写入数据需要先找到写入的位置,然后写入到磁盘,所以磁盘操作是随机IO
产生的redo log是直接写入到磁盘中呢
不是的。在执行一个1事务的过程中,产生的redo log也不是直接写入到磁盘中的,因为会产生大量IO操作,而磁盘的运行速度远小于内存。所以redo log需要自己的缓存redo log buffer,每当产生一条redo log的时候,会先写入到redo log buffer中,后续在持久化到磁盘。
bin log作用
mysql在完成一条更新操作后,Server层,还会生成一条bin log,之后事务提交的时候,会将该事务执行过程中产生的所有bin log(二进制的形式)统一写入到bin log日志中。
bin log文件是记录所有数据库表结构变更和数据修改的日志。
bin log和redo log区别
适用对象不同:
- bin log是Mysql的Server层实现的日志,所有的存储引擎都可以使用
- redo log只在InnoDB大的存储引擎中实现的日志1
文件格式不同:
- bin log有3中格式类型,STATEMENT(默认格式)、ROW、MIXED区别如下:
-
- STATEMENT:每一条修改SQL都会被记录
- ROW:记录行数据修改前和修改后的情况
- MIXED:是一种混合模式,会根据不同的情况选择使用 STATEMENT 或 ROW 格式
- redo log是物理日志,记录着某个数据页在做什么修改,比如对XX表空间的XX数据页XXX偏移量的地方做了XX的更新
写入时机不同:
- bin log在写入是由事务提交触发
- redo log在数据修改的时候触发