Mysql之DELETE操作对应的undo日志方式

 更新时间:2025年08月18日 09:38:46   作者:小志的博客  
InnoDB通过正常记录链表和垃圾链表管理数据页,删除记录先标记为deletemark,后由purge线程移入垃圾链表回收空间,PAGE_FREE指向垃圾链表头,PAGE_GARBAGE记录可重用空间大小,Undo日志保存trx_id和roll_pointer,用于版本控制和回滚

一、正常记录链表

记录的头信息中的next_record属性组成一个单向链表,我们把这个链表称为正常记录链表。

二、垃圾链表

被删除的记录其实也会根据记录头信息中的next_record属性组成一个链表,只不过这个链表中的记录所占用的存储空间可以被重新利用,所以也称这个链表为垃圾链表。

三、PAGE_FREE的作用

Page Header部分中有一个名为PAGE_FREE的属性,它指向由被删除记录组成的垃圾链表中的头节点。每删除一条记录,则该记录都会插入到垃圾链表的头节点处。

示例:有3条正常记录和2条被删除记录,他们在页中的记录分布情况如下图所示: 

注:在垃圾链表中,这些记录占用的存储空间可以被重新利用。

四、删除一条记录的步骤

delete mark阶段

仅仅将记录的deleted_flag标识位设置为1,但是这条记录并没有加入到垃圾链表中。

也就是说,这条记录即不是正常记录,也不是已删除记录。

在删除语句所在的事务提交之前,被删除的记录一直都处于这种中间状态(其实主要是为了实现MVCC的功能才这样处理的)。

  • 如下图所示:

purge阶段

当该删除语句所在的事务提交后,会有专门的线程来把该记录从正常记录链表中移除,并加入到垃圾链表中作为头节点。

  • 如下图所示:

五、关于垃圾链的重用空间的知识点了解

1、PAGE_GARBAGE是做什么的

Page Header部分有一个名为PAGE_GARBAGE的属性。该属性记录着当前页面中可重用存储空间占用的总字节数。

每当有已删除记录加入到垃圾链表后,都会把这个PAGE_GARBAGE属性的值加上已删除记录占用的存储空间大小。

2、如何重用垃圾链表的存储空间

  • PAGE_FREE指向垃圾链表的头节点,每当新插入数据的时候:
  • 首先:判断垃圾链表头节点记录的存储空间是否足够容纳这条新插入的记录。如果可以容纳则直接重用这条已删除记录的存储空间。
  • 其次:如果不能容纳,则直接向页面申请新的空间来存储这条记录。(是的,你没看错!并不会尝试遍历垃圾链表,以找到可以容纳新记录的节点)

3、如果新插入的那条记录记录小于重用的记录空间,那么会有一部分空间用不到,怎么处理?是否可以直接浪费掉?

这种情况会频繁发生,也就会随着记录越插越多而产生越来越多的空间碎片。只有当页面块满的时候,如果再插入一条新记录,无法分配一条完整的记录空间时,会先查看PAGE_GARBAGE的空间和剩余空间相加是否可以容纳这条新的记录,如果可以,InnoDB则会尝试重新组织页内的记录。即:先开辟一个临时页面,把原页面内的记录依次挨着插入一遍到临时页,之后,再把临时页的内容复制到本页面,这样就可以把那些碎片空间都释放出来了。但是该操作比较耗费性能。

由于一旦事务提交,我们也就不需要再回滚这个事务了,所以在设计undo日志时,只需要考虑delete mark这个阶段所做的影响进行回滚就可以了。

  • TRX_UNDO_DEL_MARK_REC类型的undo日志结构如下图所示:

上图解释:

  • info bits:记录头信息的前4个比特的值。
  • trx_id:旧记录的trx_id值。
  • roll_pointer:旧记录的roll_pointer值。
  • len of index_col_info:也就是下边的【索引列各列信息】部分和本部分占用的存储空间总和。
  • 索引列各列信息 <pos, len, value>列表:凡是被索引的列的各列信息。

4、什么TRX_UNDO_DEL_MARK_REC类型的undo日志保存旧记录的trx_id值和roll_pointer值

保存旧记录的trx_id值——为了采用事务id作为版本号,记录每个undo日志所对应的版本是多少。

保存旧记录的roll_pointer值——可以通过undo日志的roll_pointer属性找到上一次对该记录进行改动时产生的undo日志,因此可以将日志串成链表。这个链表就是版本链。

  • 示例:新增一条记录,然后再删除这条记录的完整操作过程,如下所示:

六、删除操作生成undo日志的示例

1、 先插入两条记录

BEGIN; # 显示开启一个事务,假设该事务的事务id为100
# 插入两条记录
INSERT INTO sys_user(id, name, city) VALUES(1, 'xz','北京市'), (2, 'tom','天津市');
# 删除一条记录
DELETE FROM sys_user WHERE id = 1;

2、上图字段说明

(1)、索引列各列信息 <pos, len, value>列表<0, 4, 1>:

  • 由于id列是主键,所以pos=0;
  • 由于id列的类型是INT,所以len=4;
  • 由于id=1,所以value=1;

(2)、索引列各列信息 <pos, len, value>列表<3, 4, ‘xz’>:

  • 由于name列是二级索引,它排在id列、trx_id列、roll_pointer列之后,所以pos=3;
  • 由于id列的类型是INT,所以len=4;
  • 由于name=‘xz’,所以value=‘xz’;

(3)、len of index_col_info

  • pos使用1字节来存储。
  • len使用1字节来存储。
  • value根据具体值,来判断。比如:id=1,主键是INT占4个字节,所以value使用4字节存储。name=‘xz’,VARCHAR类型,所以value用4字节存储。
  • len of index_col_info本身占2个字节。

(4)、综上所述,<0, 4, 1><3, 4, ‘xz’>占用空间等于:(1+1+4)+(1+1+4) =12,如下图所示:

(5)、最后,再加上len of index_col_info属性本身占2个字节,所以总共14字节。即:len of index_col_info=14。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 记一次mysql5.7测试数据库被删表的问题

    记一次mysql5.7测试数据库被删表的问题

    这篇文章主要介绍了记一次mysql5.7测试数据库被删表的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • MySQL数据库复合查询与内外连接图文详解

    MySQL数据库复合查询与内外连接图文详解

    本文详细介绍了在SQL中进行多表查询的技术,包括笛卡尔积、自连接、子查询、内连接和外连接等,文章还解释了union和unionall的区别,以及如何在from子句中使用子查询,这些技术对于处理复杂的数据库查询非常重要,可以有效地从不同表中提取和组合数据,需要的朋友可以参考下
    2024-10-10
  • MySQL修改安全策略时报错:ERROR 1193 (HY000)的解决办法

    MySQL修改安全策略时报错:ERROR 1193 (HY000)的解决办法

    这篇文章主要给大家介绍了关于MySQL修改安全策略时报错:ERROR 1193 (HY000): Unknown system variable ‘validate_password_policy‘的解决方法,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • MySQL8新特性:持久化全局变量的修改方法

    MySQL8新特性:持久化全局变量的修改方法

    这篇文章主要给大家介绍了关于MySQL 8新特性:持久化全局变量的修改的相关内容,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • mysql插入中文数据变成问号的解决方案

    mysql插入中文数据变成问号的解决方案

    这篇文章主要介绍了mysql插入中文数据变成问号的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • MySQL中的IF语句使用小结

    MySQL中的IF语句使用小结

    在MySQL数据库中,IF 语句是一种常见的条件控制语句,本文介绍了 MySQL 中 IF 语句的基本用法以及实际应用场景,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • MySQL5.7.16绿色版安装教程详解

    MySQL5.7.16绿色版安装教程详解

    这篇文章主要介绍了MySQL5.7.16绿色版安装教程详解的相关资料,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2016-10-10
  • 使用MySQL实现一个分布式锁

    使用MySQL实现一个分布式锁

    在分布式系统中,分布锁是一个最基础的工具类。这篇文章主要介绍了用MySQL实现一个分布式锁,本文通过实例代码相结合给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12
  • MySQL之使用UNION和UNION ALL合并两个或多个SELECT语句的结果集

    MySQL之使用UNION和UNION ALL合并两个或多个SELECT语句的结果集

    这篇文章主要介绍了MySQL之使用UNION和UNION ALL合并两个或多个SELECT语句的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • MySQL笔记之系统信息函数详解

    MySQL笔记之系统信息函数详解

    本篇文章对MySQL系统信息函数进行了详解的介绍。需要的朋友参考下
    2013-05-05

最新评论