首页 > 数据库 >redo log-Transaction(2)—mysql进阶(六十)

redo log-Transaction(2)—mysql进阶(六十)

时间:2022-11-01 17:36:28浏览次数:48  
标签:Transaction log 记录 mtr mysql 日志 redo block 进阶


前面我们说了为了吧buffer pool的数据持久化到磁盘上,比如修改了一条数据,不可能每次吧整个页的数据都刷新过去,这样耗费性能,innoDB就是把修改的数据记录在redo日志里,redo日志格式主要是spaceId,type,page_number,offset,Data等。Offset记录上一条数据的地址,为了修改上一条记录头部新的next record,data记录的就是真实数据。Redo日志主要关注的就是一条语句修改了多少b+树,针对其中某颗树,可能增加了页,也可能更新了叶子节点或者内节点。他会记录修改日志或者删除日志,而删除日志格式又会分为开始和结束,MLOG_COMP_LIST_START_DELETE和MLOG_COMP_LIST_END_DELETE。

​​redo log(1)—mysql进阶(五十九)​​

Mini-transaction

以组的形式写入redo日志

一个sql语句可能修改若干个页面,比如我们前面说的一条insert语句可能修改系统表空间页号为7 页面的max row id属性,还会更新b+树聚簇索引和二级索引对应的页面。由于这些都是发生在buffer pool里,这时候都需要记录在redo日志里,于是在记录的时候,innoDB又把这些分为不同的组。

修改max row_id是不可分割的,向聚簇索引对应的b+树插入一条记录产生的redo日志不可分割,向某个二级索引b+树插入一条记录产生的redo日志不可分割,还有一些其他页面生成的redo日志不可分割。。。

怎么理解不可分割呢,我们向某个索引对应的b+树插入一记录,在插入b+树之前,需要定位向哪个叶子节点代表的数据页,定位到具体的数据页后,有两种可能:

情况一:该数据页的剩余空闲空间充足,足够容纳这一条待插记录,这种就很简单,直接把记录插入这个数据页,记录一条MLOG_COMP_REC_INSERT记录到redo日志,我们吧这种情况称为乐观插入。

情况二:该数据页的剩余空间不足,那么这时候就需要进行所谓的页分裂操作,也就是新建一个叶子节点,插入一条10的记录,那么比10大的记录都会移到新建的叶子节点,吧10插到前面的叶子节点,如果内节点不够用,则同样也需要分裂,这样会记录更多的redo日志,我们称这种为悲观插入。对于这些,我们还需要修改各种段,区的统计信息,各种链表的统计信息,(比如free链表,fsp_free_page链表等等),反正有二三十条记录。

这些操作肯定必须是原子性的,比如不能在系统宕机的时候,redo日志吧聚簇索引的修改记录恢复,而二级索引的修改记录未恢复,这种必定导致数据错误,形成不完成的b+树。如何保证原子性呢,于是innoDB规定这些操作必须以【组】的形式来记录到redo日志,在系统宕机重启时候,要么全部一起恢复,要么一条都不恢复。那么怎么做到呢:

当悲观插入,需要记录多条redo日志。innoDB解决办法是,每次一组日志之后,记录一条特殊的redo日志,MLOG_MULTI_REC_END,type字段对应的十进制数字为31,该类型的结构很简单,只有一个type字段。所以当系统崩溃时候,只有解析到MLOG_MULTI_REC_END才会算是一组完整的操作,如果没有解析到MLOG_MULTI_REC_END,则之前解析的都放弃。

如果有的操作只记录一条数据,然后海特意记录一条MLOG_MULTI_REC_END,不是很浪费吗,这时候如果type字段的第一个比特位是1,代表需要该原子性操作只需要操作一条redo日志。

Redo日志写入过程

Redo log block

innoDB为了更好的进行系统恢复,他们吧通过mtr生成的redo日志都放在大小为512个字节的页中,为了和我们前面表空间的数据页做区别,所以redo日志的页我们称为block(其实他们是差不多的)。Redo log block的结构如下,

log block header:12个字节。

Log block body:496个字节。

Log block trailer:4个字节。

其中redo日志主要存储在body里,我们在看看header 和trailer

Log block header 分为四个属性:

  1. log_block_hdr_no:4个字节,每个block都有一个大于0的唯一标号,本属性就代表唯一值。
  2. log_block_hdr_data_len:表示已经存入redo日志已经使用的字节,从12个字节开始,因为log block body是从12个字节处开始,如果log block body全部填满了,则记录是512字节。
  3. log_block_first_rec_group:多条redo日志会生成一个记录组redo_log_record_group,这个log_block_first_rec_group就代表mtr生成redo日志记录组的偏移量。
  4. log_block_checkpoint_no:表示所谓checkpoint的序号,后面着重介绍。

Log block trailer分为一个属性:

Log_block_checksum:表示block的效验值,用于正确性效验。

Redo日志缓冲区

我们前面说过,为了存储数据到磁盘,会有一个数据的缓冲区buffer pool,同理,redo日志也不能直接写到磁盘,而是需要在mysql启动前,申请一个redo log buffer的连续内存空间(redo日志缓冲区),可以称为log buffer,这篇区域划分为若干个redo log buffer。

可以通过设置启动参数innoDB_log_buffer_size来制定log_buffer的大小,在mysql5.7.21这个版本,默认参数是12mb。

Redo日志写入log buffer

向log buffer 写入redo日志是顺序的,先往前面的block中写,当前面的block满了之后,就往后面空的写,所以如何定位到空的block呢,第一个问题就是block的偏移量,所以innoDB提供了一个buf_free的全局变量来记录block的偏移量,指明redo日志写入的位子。

我们前面说了一个mtr执行过程中可能产生若干条redo日志,这些日志都是不可分割的组,所以并不是每生成一条redo日志,就将其插入log buffer中,而是将mtr产生的日志先存到一个地方,当mtr结束的时候,再将产生的一组数据全部赋值到log_buffer中。

假设我们现在有两个名为T1/T2的事务,每个事务包含两个mtr,我们给mtr命名一下:

事务T1的两个mtr分别为mtr_t1_1和mtr_t1_2。

事务T2的两个mtr分别为mtr_t2_1和mtr_t2_2。

不同的事务可能并发执行,所以T1和T2的mtr可能交替执行,每当一个mtr执行完毕,伴随着该mtr生成的一组redo日志就需要复制到log buffer 中,也就是说不同事务的mtr可能是交替写入log buffer中的。

标签:Transaction,log,记录,mtr,mysql,日志,redo,block,进阶
From: https://blog.51cto.com/u_15856702/5814527

相关文章

  • springBoot+mysql实现用户权限控制--系统框架搭建(四)
    上篇文章说了AOP实现上下文的存储,有需要的可以看看,​​AOP实现上下文存储---系统框架搭建(三)​​环境需求:springboot+mysql5.7.16+Lombok1.18.121、需求背景为了实......
  • transaction (2)—mysql进阶(五十八)
    上篇文章说了acid四个事务的特性,原子性保证要不两个sql一起执行,要么不执行,隔离性,两个事务之间必须互不干扰,一致性,两边的数据必须保持一致,可以说一致性的前提是原子性和隔离......
  • MySQL中Delete和Truncate区别
    一、清空表语句truncatetable[表名];deletefrom[表名]where…; 二、相同点两者都是删除表数据但不会删除表结构 三、不同点delete支持按条件删除,TRUNCA......
  • python-绘图进阶
    数据准备importmatplotlib.pyplotaspltimporttushareastsimportpandasaspdimportdatetime%matplotlibinlineplt.rcParams['font.sans-serif']=['Arial......
  • mysql8初始化及账户管理
    查看初始密码:grep'temporarypassword'mysqld.logmysql>alteruser'root'@'localhost'identifiedby'密码';mysql>updatemysql.usersethost="%"whereuser="r......
  • 关于mysql编码
     参考原文地址:https://www.cnblogs.com/beiyeren/p/3835412.html在开发程序的时候,我们使用mysql数据库开发的时候,有时会碰到自己明明输入的是中文,为什么数据库中存储的......
  • mysql explain 执行计划
    分析查询语句的执行情况,可以分析出所查询的表的一些特征  mysql>EXPLAIN/DESCRIBE/DESCSELECT*FROM......; mysql>DESCSELECT*FROMusers\G******......
  • MySQL 复制
    MySQL复制MySQL从3.23版本开始提供复制的功能。复制是指将主数据库的DDL和DML操作通过二进制日志传到复制服务器(也叫从服务器)上,然后在从服务器上对这些日志重新执......
  • @Transactional和try-catch一起使用造成事务回滚失效
    同时使用@Transactional和try-catch,发现执行以下代码事务会失效,数据还是进行了修改操作1@Override2@Transactional(rollbackFor=Exception.class)3pub......
  • MySQL InnoDB 行记录格式(ROW_FORMAT)
    1 问题描述公司某游戏日志监控报警,查看日志显示如下错误:Rowsizetoolarge(>8126).ChangingsomecolumnstoTEXTorBLOBorusingROWFORMAT=DYNAMICorROWFORMAT=......