MySQL知识总结
《MySQL是怎样运行的》知识总结
20 undo日志
事务的回滚需求
事务需要保证原子性
,如果事务的执行过程,服务器发生了错误,就需要将事务进行回滚(对部分语句进行回滚,对整个事务进行回滚)。
InnoDB把为了回滚而记录的东西称为undo日志,对数据库进行改动(insert、delete、update)操作时,就需要进行记录,不同的操作类型产生的undo日志的格式是不一样的。
- 插入操作,记录主键值,回滚时只需要根据主键值将相应的记录删除
- 删除操作,把记录的内容记录,回滚时把删除前记录的内容重新插入
事务Id
分配Id的时机
- 读写事务,只有在它第一次对某个表执行改动操作时,才分配事务Id
- 只读事务,只能对
临时表
进行改动操作 - 如果不为事务分配Id,则事务Id为默认值0。
事务Id的生成
事务Id与隐藏列row_id
的分配策略类似,MySQL会维护一个全局变量,为事务分配Id后,就自增1,当它的值为256的倍数时,就会刷新到系统表空间页号为5的页面属性Max Trx ID
(占8字节)中。
系统启动时,会将这个属性加载到对应的全局变量并加上256,这样就保证事务Id是递增的。
记录的隐藏列
聚簇索引
的记录除了会有用户定义的列外,还会有额外的隐藏列
row_id
:作为主键Id(如果表中没有主键、或不可为Null的唯一索引)trx_id
:事务Idroll_pointer
:回滚指针,指向记录对应的undo日志
undo日志的格式
为了保证事务的原子性,InnoDB在对记录进行改动操作时,需要创建相应的undo日志,一个事务执行过程中,可能会新增、修改、删除多条
记录,所以需要记录多条undo日志,undo日志会从0开始编号。
undo日志会存储在fil_page_undo_log
类型的页面中。
插入操作的undo日志
插入一条记录的结果是记录被加入到数据页中,在创建对应undo日志时,只需要把这条记录的主键值记录下来
,如果要回滚插入操作,只需要根据对应的主键值对记录进行删除操作。
trx_undo_insert_log类型的undo日志
end of record
:本条记录的结束(即指向下一条日志开始)undo type
:日志的类型undo no
:日志对应的编号,一个事务中,日志编号从0开始,事务没提交,事务中产生的undo日志的编号递增1table id
:日志记录对应的表的Id主键列的信息列表
:<列占用的字节数,对应的值>start of record
:本条记录的开始(即指上一条日志结束)
提示
向表插入记录时,实际上需要向聚簇索引、所有的二级索引都插入记录,不过,只需要针对主键值创建1条undo日志,在回滚插入操作时,只需要知道这条记录的主键信息,根据主键信息对聚簇索引、二级索引相应的记录删除。
InnoDB对undo日志的某些属性进行了压缩处理。
删除操作的undo日志
插入到数据页面的记录会根据记录头信息next_record
组成一个单向链表(正常记录链表)。
被删除的记录是根据next_record
属性组成了垃圾链表
,数据页结构Page Header
中有属性page_free
指向垃圾链表的头节点
。
删除操作的2个阶段
delete mark
:将记录的