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

Read View 是什么,不是什么
Read View 不是 MySQL 里某个可配置的开关,也不是你 CREATE TABLE 时能指定的选项。它是 InnoDB 在执行 SELECT(快照读)时,**当场生成的一个内存结构**,用来决定“这一行数据对当前事务是否可见”。它不持久、不共享、不缓存——每次快照读都可能新建一个(取决于事务隔离级别和状态)。
容易踩的坑:误以为 START TRANSACTION 后立刻固定了 Read View;其实只有第一次快照读才创建,后续同事务内 SELECT 复用它——但 SELECT ... FOR UPDATE 或 UPDATE 这类当前读不走它。
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 id和Trx read view行(仅 debug 版本或特定编译选项下可见) - 构造典型场景:两个事务分别插入/更新同一行,用
SLEEP(2)控制时序,在 RR 下两次SELECT结果一致,在 RC 下可能不同 - 注意:
information_schema.INNODB_TRX里的TRX_ID是事务 ID,不是 Read View 快照内容;别把它和可见性判断混为一谈
最常被忽略的是:Read View 只作用于聚簇索引记录的 DB_TRX_ID 字段比较,二级索引不存事务 ID,所以通过二级索引查找时,InnoDB 会回表到聚簇索引再判断可见性——这会影响执行计划和性能,尤其在覆盖索引失效时。










