mrr是mysql 5.6引入的优化机制,通过将二级索引回表请求按主键排序批量读取,减少磁盘随机i/o;需满足范围扫描、回表行数多、optimizer_switch启用且存储引擎支持等条件才生效。

什么是 MRR(Multi-Range Read)优化
MRR 是 MySQL 5.6 引入的优化机制,核心作用是把原本随机的二级索引回表请求,重排成按主键顺序的批量读取,减少磁盘随机 I/O。它不是自动开启的“银弹”,而是一个受 optimizer_switch 控制、且只在特定条件下触发的策略。
什么时候 MRR 会真正生效
MRR 只在满足全部以下条件时才启用:
- 查询使用了二级索引做范围扫描(如
WHERE status BETWEEN 1 AND 5),且后续需要回表查完整行 - 优化器估算出回表行数较多(通常 > 10 行,具体阈值由
read_rnd_buffer_size和行大小共同决定) -
optimizer_switch中mrr=on且mrr_cost_based=on(后者表示启用成本评估,默认开启) - 存储引擎支持:InnoDB 和 MyISAM 支持,但 MyISAM 的 MRR 效果有限
常见误判:EXPLAIN 显示 Using index condition 或 Using where ≠ 启用了 MRR;必须看到 Using MRR 才算真正生效。
怎么确认和强制控制 MRR 行为
检查当前设置:
SELECT @@optimizer_switch\G
临时开启/关闭(仅当前会话):
SET optimizer_switch='mrr=on,mrr_cost_based=off';
注意:mrr_cost_based=off 会跳过成本评估,强制启用 MRR——但可能适得其反,尤其当回表行数很少时,排序+缓冲反而增加开销。
影响 MRR 效果的关键配置:
-
read_rnd_buffer_size:越大越可能触发 MRR,但上限受线程内存限制;默认 256K,高并发下不宜设过大 -
join_buffer_size不影响 MRR,别混淆 - InnoDB 层无独立开关,完全依赖优化器决策
MRR 带来的实际性能变化和陷阱
MRR 在 SSD 上收益有限,在 HDD 上更明显;但现代云数据库多用 NVMe,实际提升常不如预期。
容易踩的坑:
- 复合索引中范围条件写在中间或末尾(如
INDEX(a,b,c)+WHERE a=1 AND b > 2 AND c ),MRR 可能不触发,因为优化器认为范围太窄 - 使用
SELECT *且表宽较大时,read_rnd_buffer_size很快被撑满,导致分批多次排序,反而比朴素回表还慢 -
ORDER BY涉及非主键字段时,MRR 生成的有序主键序列无法复用,最终仍要额外排序
真正值得调的是索引设计本身——让范围扫描尽可能落在索引最左前缀上,比依赖 MRR 更可靠。










