mysql如何使用Read View控制可见性_mysql事务快照读解析

2次阅读

read view 是 innodb 执行快照读时当场生成的内存结构,用于判断数据行对当前事务是否可见;它非配置项、不持久、不共享,rr 级别下首次快照读创建并复用,rc 级别下每次快照读重建。

mysql如何使用Read View控制可见性_mysql事务快照读解析

Read View 是什么,不是什么

Read View 不是 mysql 里某个可配置的开关,也不是你 CREATE table 时能指定的选项。它是 InnoDB 在执行 select(快照读)时,**当场生成的一个内存结构**,用来决定“这一行数据对当前事务是否可见”。它不持久、不共享、不缓存——每次快照读都可能新建一个(取决于事务隔离级别和状态)。

容易踩的坑:误以为 START TRANSACTION 后立刻固定了 Read View;其实只有第一次快照读才创建,后续同事务内 SELECT 复用它——但 SELECT ... for UPDATEUPDATE 这类当前读不走它。

RR 隔离级别下 Read View 的生成时机

REPEATABLE READ 下,Read View 在事务中**第一次执行快照读时生成**,之后复用。这意味着:

  • 事务 A 执行 SELECT → 生成 Read View,记录当时活跃事务 ID 列表(m_ids)、最小未提交事务 ID(min_trx_id)、最大已提交事务 ID(max_trx_id)等
  • 事务 B 在此之后提交的修改,对事务 A 的后续 SELECT 不可见——哪怕 B 的 ID 小于 A 的 min_trx_id
  • 但如果事务 A 先执行 SELECT ... FOR UPDATE(当前读),再执行普通 SELECT,后者仍用原 Read View,不会因锁读而刷新

关键点:不是“事务开始时”建 Read View,而是“第一次快照读时”。空事务(只 BEGIN 不查)不触发,也不影响后续视图一致性。

RC 隔离级别下 Read View 每次都新建

READ COMMITTED 的行为截然不同:**每次快照读都重建 Read View**。所以:

  • 事务 A 第一次 SELECT 看不到事务 B 的未提交修改
  • B 提交后,A 再执行一次 SELECT 就能看到新数据——因为新建的 Read View 中,B 的事务 ID 已不在 m_ids
  • 这也意味着 RC 下无法避免“不可重复读”,但能避免“脏读”

性能影响:频繁快照读会多一次内存分配和活跃事务扫描(遍历 trx_sys->rw_trx_list),高并发下比 RR 略重,但换来语义清晰性。

如何验证当前事务的 Read View 内容

InnoDB 不提供 SQL 接口直接 dump Read View,但可通过调试或间接方式观察效果。常用验证手段:

  • 开启 innodb_status_output = ON,查 SHOW ENGINE INNODB STATUS,在 “TRANSACTIONS” 部分找当前事务的 Trx idTrx read view 行(仅 debug 版本或特定编译选项下可见)
  • 构造典型场景:两个事务分别插入/更新同一行,用 SLEEP(2) 控制时序,在 RR 下两次 SELECT 结果一致,在 RC 下可能不同
  • 注意:information_schema.INNODB_TRX 里的 TRX_ID 是事务 ID,不是 Read View 快照内容;别把它和可见性判断混为一谈

最常被忽略的是:Read View 只作用于聚簇索引记录的 DB_TRX_ID 字段比较,二级索引不存事务 ID,所以通过二级索引查找时,InnoDB 会回表到聚簇索引再判断可见性——这会影响执行计划和性能,尤其在覆盖索引失效时。

text=ZqhQzanResources