开一个持有快照的长事务,看它真实怎么阻止undo被回收,再诚实记录它结束之后Purge赶上来的真实时间到底有多不确定。
session A(长事务,持有快照约8秒)START TRANSACTION WITH CONSISTENT SNAPSHOT; SELECT amount FROM orders WHERE id=1; SELECT SLEEP(8); session B(在A存活期间真实提交一次更新)UPDATE orders SET amount = amount + 0.01 WHERE id = 1;
A开启快照之前: History list length = 0 B执行UPDATE并提交,A仍存活: History list length = 1 ← 真实多了这一条 同时验证MVCC正确性(同一个事务A内): 第一次读:amount = 148.08 (B已提交,改成了148.09) 第二次读(仍在A内):amount = 148.08 ← 真实还是旧值,undo真实保住了这个版本
B的这次提交真实产生了一条undo log记录(用来保留amount更新前的旧值),因为A这个时候还持有一个更早的快照,理论上随时可能需要读到这个旧值,所以这条undo记录真实不能被回收——History list length从0变成1,正是"这条undo还没被清理"的直接体现,也和A自己在事务内真实读到的旧值(148.08)吻合。
A COMMIT之后(长事务结束,理论上这条undo已经没人需要了): 第一次真实测试: 10秒后仍是1,一路测到65秒仍是1,没有在观察窗口内清零 第二次真实测试: 10秒后就已经是0,清零发生在观察窗口之内 两次测试的唯一区别:Purge后台线程真实调度的时机,不是A提交那一刻
每一步都是本文上面用真实并发会话跑出来的原始结果。
SHOW ENGINE INNODB STATUS里的History list length,配合真实的多轮重复观测