undo log有两个作用:提供回滚和MVCC。
undo log是逻辑日志。
undo log存在于一个特殊的段中,存在于表空间中,和主键id组织的数据存在一个文件中,毕竟每行数据都有个指向undo log的指针。
4)都说redo是物理日志(绝大部分是,不纠结),undo是逻辑日志,并且你新增,undo log会记录删除,你更新他会记录相反的更新,
这里有两个点,怎么理解物理日志和逻辑日志,怎么理解是记录相反操作,新增和删除相反可以理解,那更新x = x - 10相反难道是x = x
+ 10,你减去10,相反我就给你加上10,我相信肯定好大一部分人都这么理解,这么理解就坑大了。
redo确实绝大部分是物理日志,物理日志的意思就是有个日志文件存放,记录了每个物理地址目前的值到底是多少,
至于undo log,如果一个新增操作,undo log记录的是一个删除类型,甚至都不需要copy任何数据,当读到这个版本,发现了删除标记,
就可以直接返回null了
如果是个更新操作,那么copy一下更新前的值,没有更新的当然不用copy,也并不需要记录某个物理地址上是某个特定的值,当你读到这个undo log,那么就把读到的数据根据需要更新成undo log里对应的数据就行了。
如果是一个删除操作,则将这行记录copy到undo log中,然后将原始数据标记成已经删除。
这种日志难道不能看成是一种逻辑日志吗,与当前操作相反的一种逻辑日志,不需要记录对应物理地址上是些什么内容的逻辑日志。
当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
有时候应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时
它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
undo log的存储方式
innodb存储引擎对undo的管理采用段的方式。rollback segment称为回滚段,每个回滚段中有1024个undo log segment。
在以前老版本,只支持1个rollback segment,MySQL5.5可以支持128个rollback segment,即支持128*1024个undo操作,还可以通过变量 innodb_undo_logs自定义多少个rollback segment,默认值为128。
undo log默认存放在共享表空间中。
默认rollback segment全部写在一个文件中,但可以通过设置变量 innodb_undo_tablespaces平均分配到多少个文件中。
delete/update操作的内部机制
当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。
但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。
并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。
通过undo log记录delete和update操作的结果发现:
delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
update分为两种情况:update的列是否是主键列。
如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。
如果是主键列,update分两部执行:先删除该行,再插入一行目标行。
insert undo log和update undo log为啥要分开,为啥提交之后insert undo log可以直接删除了,update undo log需要等待purge?
如果某个事务ID=100新增了一条记录,那么在这个事务版本之前这个记录是不存在的
这条数据要么是事务100提交的,然后就存在这条数据了
事务100没有提交,这条数据是nul
这条数据本身就是一个版本,要么是不存在,读取不到,要么就是存在,可以读取
数据是否存在,在RC和RR级别看事务有没有提交。
undo log 分成两种格式
一种给insert操作。记录中不含回滚指针,不含旧值。insert之前是没有的。
一种给update/delete操作。有回滚指针,有旧值。
对于INSERT_UNDO,调用函数trx_undo_page_report_insert进行插入,记录格式大致如下图所示:
对于UPDATE_UNDO,调用函数trx_undo_page_report_modify进行插入,UPDATE UNDO的记录格式大概如下图所示: