MySQL MRR本质是将随机回表转为顺序回表,通过缓存并按主键排序二级索引查出的主键值,再批量顺序读取聚簇索引,降低机械硬盘寻道开销;需满足二级索引范围扫描、非覆盖索引且优化器选择才生效,EXPLAIN中出现Using MRR标志启用成功。

MySQL MRR 本质是把随机回表变成顺序回表
MRR 不减少回表次数,也不跳过回表动作——它只是改变回表的访问模式。二级索引查出一批 主键值 后,原本会按索引顺序逐个去聚簇索引里找对应行(id=105 → id=23 → id=891 → …),这种跳跃式访问在机械硬盘上代价极高。MRR 把这批主键先缓存、排序(比如变成 id=23, 105, 891, … → id=23, 105, 891 按主键升序排列),再按这个顺序批量读取,让磁盘头移动更少、寻道时间大幅下降。
EXPLAIN 中看到 Using MRR 才算真正生效
仅开启配置不等于查询就走 MRR。必须同时满足:查询走的是二级索引范围扫描(type 为 range、ref 或 eq_ref),且需要回表(即非覆盖索引);优化器估算成本后认为 MRR 更优。检查方式很直接:
- 执行
EXPLAIN SELECT ...,观察Extra列是否含Using MRR - 若只有
Using index condition,说明 ICP 生效了,但 MRR 没参与 - 若
type是ALL或index,MRR 根本不会触发
read_rnd_buffer_size 大小直接影响 MRR 效果
这个缓冲区决定一次能缓存多少主键用于排序。太小(如默认 256KB)会导致频繁分批、多次排序+回表;太大可能挤占其他线程内存,甚至触发 swap。真实调优要结合单行主键 + 二级索引字段大小 × 预估回表行数估算:
- 例如主键是
BIGINT(8 字节),二级索引字段共 20 字节,预计回表 1 万行 → 至少需 (8+20)×10000 ≈ 280KB,建议设为512KB或1MB - 线上调整优先用
SET SESSION read_rnd_buffer_size = 1048576,避免影响全局 -
ROW_FORMAT必须是DYNAMIC或COMPACT,REDUNDANT不支持 MRR
MRR 对 SSD 和缓存命中场景几乎无收益
它的价值集中在机械硬盘 + 大表 + 缓存未命中的组合场景。SSD 的随机 I/O 延迟极低,排序+顺序读带来的优势被抹平;如果数据全在 innodb_buffer_pool 里,物理 I/O 本身不存在,MRR 就只是多做了次内存排序。所以别在纯 SSD 环境或高缓存命中率业务里强行调大 read_rnd_buffer_size——没效果还浪费内存。


















