rc与rr核心区别在于读视图生成时机:rc每次select新建快照,rr事务首次select即固定快照;前者降低版本链遍历开销、减少锁范围、加快undo清理,后者易致purge延迟、锁冲突加剧及主从延迟。

RC级别每次SELECT都用最新已提交快照,RR级别整个事务只用一个快照
核心区别不在“锁多锁少”,而在“读视图生成时机”。RC下,SELECT执行时才基于当前所有已提交事务ID构建Read View;RR下,事务第一次SELECT时就固定了Read View,后续所有读都复用它。
这意味着:在高并发写场景中,RC能更快感知其他事务的提交结果,不需要维护长生命周期的版本链;而RR必须保留从事务启动起所有被它“看到过”的旧版本undo log,直到该事务结束——这会拖慢purge线程,加剧undo tablespace膨胀和版本链遍历开销。
RC默认不加间隙锁(Gap Lock),RR在范围查询时自动加Next-Key Lock
如果你执行的是非唯一条件的SELECT ... FOR UPDATE或UPDATE WHERE age > 25这类范围操作:
- 在RR下,InnoDB会用
Next-Key Lock(记录锁 + 间隙锁)封锁索引区间,防止幻读,但会显著扩大锁范围,增加锁冲突概率 - 在RC下,InnoDB只对实际命中的记录加行锁(
Record Lock),不加间隙锁——除非显式使用SELECT ... LOCK IN SHARE MODE或FOR UPDATE且满足特定条件
所以RC在范围DML场景下锁粒度更细,事务等待更少,尤其在高并发插入/更新热点区间的表上,表现更稳。
RC减少MVCC版本链遍历深度,降低CPU和内存压力
每次读取时,InnoDB要沿着undo log版本链往前找,直到遇到第一个对当前事务不可见的版本。RR因快照长期有效,可能需遍历几十甚至上百个历史版本;RC因快照短命,通常只需比对最近几次提交,链长平均更短。
这个差异在以下情况会被放大:
- 事务持续时间长(比如未及时
COMMIT的交互式会话) - 写入频繁、
autocommit=0且习惯性大事务 - 表上有高频
UPDATE/DELETE且WHERE条件不走索引(导致全行版本检查)
RC下binlog写入更轻量,主从延迟风险更低
虽然MySQL 5.7+默认binlog_format=ROW,但RR隔离级别仍会间接影响复制行为:
- RR要求语句级一致性更强,在某些早期
STATEMENT格式或混合模式下,可能触发额外锁或临时表 - 更重要的是:RR下长事务导致的
undo log堆积,会让备库apply时面临更复杂的版本回溯逻辑,尤其在并行复制worker处理同一张表的不同分区时 - RC因快照生命周期短,
undo log可被purge得更及时,备库回放压力更平滑
这不是binlog本身变小,而是MVCC清理节奏与复制节奏更匹配。
真正卡性能的往往不是“RR vs RC”这个开关本身,而是开发者没意识到:开启RR后,还写了一堆20秒不COMMIT的事务,或者在RR下滥用SELECT ... FOR UPDATE却没走索引——这时换RC只是把症状掩盖了,根子还在事务设计上。











