SQL数据库读一致性靠MVCC实现,核心是多版本快照:事务启动时生成含活跃事务列表和可见边界的时间点视图,结合行级版本链(如xmin/xmax或DB_TRX_ID/ROLL_PTR)判断数据可见性;RC每次查询建新快照,RR首次查询建快照并复用;旧版本存于undo log,需VACUUM或purge清理,长事务会阻塞清理导致性能下降。

SQL数据库的读一致性,核心靠多版本并发控制(MVCC)实现,其中“多版本快照”是关键机制。它让每个事务在启动时看到一个逻辑上一致的数据视图,不受其他并发写操作干扰,既避免了加锁阻塞,又保证了可重复读甚至快照隔离级别下的正确性。
快照如何生成:事务启动时的可见性判断
事务开始时,数据库会记录一个“快照点”,通常对应一个全局递增的事务ID(如PostgreSQL的xmin/xmax,MySQL InnoDB的Read View)。该快照包含:
• 当前活跃事务ID列表
• 已提交但早于本事务开始的最新事务ID
• 本事务自身的ID
后续所有SELECT都基于这个快照判断每行数据版本是否可见:只有满足“已提交且提交时间早于快照起点”的版本才对当前事务可见。
数据版本如何存储:行级版本链
数据库不在原地覆盖数据,而是为每次UPDATE/INSERT生成新版本,并通过隐藏字段链接成链:
• PostgreSQL:每行含xmin(插入事务ID)、xmax(删除/过期事务ID),配合clog判断事务状态
• MySQL InnoDB:每行含DB_TRX_ID(最近修改事务ID)和DB_ROLL_PTR(指向undo日志中前一版本)
旧版本实际存于undo log或专门版本区,供快照查询回溯,不污染主表数据。
隔离级别与快照行为差异
不同隔离级别复用同一套快照机制,但快照获取时机不同:
• 读已提交(RC):每次SELECT都新建快照,可能看到其他事务刚提交的新值,导致不可重复读
• 可重复读(RR):事务第一次SELECT时创建快照,后续查询复用,保障结果一致
• 快照隔离(SI):更严格规则(如禁止写偏斜),部分系统(如PostgreSQL默认RR即SI语义)
清理与性能:版本不能无限堆积
旧版本数据不会自动消失,需后台进程回收:
• PostgreSQL靠VACUUM扫描并移除对所有现存快照都不可见的行版本
• MySQL InnoDB依赖purge thread解析undo log,异步清理已无事务需要的旧版本
若长事务长期未结束,会阻止快照推进,导致undo膨胀、磁盘增长甚至查询变慢——这是MVCC最典型的运维陷阱。










