mrr启用需同时满足四个硬性条件:使用二级索引且需回表;where含范围操作符(如between、>等);优化器估算回表行数较多;mrr=on且mrr_cost_based=on。缺一不可。

MySQL执行器判断MRR可用性的核心条件
MySQL执行器不会主动“选择”MRR,而是由优化器在生成执行计划阶段,基于查询结构、索引类型和配置参数综合评估是否启用MRR。它不看SQL写得漂不漂亮,只认硬性条件是否全部满足。
必须同时满足的四个硬性条件
只要其中任意一条不成立,Using MRR 就不会出现在 EXPLAIN 的 Extra 字段里:
- 查询使用了二级索引(非聚簇索引),且该索引无法覆盖查询所需所有列(即必须回表)
- WHERE 条件中包含范围操作符:如
BETWEEN、>、、<code>IN(多值)、!=等,导致索引扫描返回多个主键ID -
optimizer_switch中mrr=on且mrr_cost_based=off(后者禁用成本估算强制启用,否则优化器可能因预估成本高而跳过MRR) - 存储引擎支持MRR:仅
InnoDB和MyISAM支持;MEMORY、COLUMNSTORE等不支持
为什么EXPLAIN没显示Using MRR?常见误判点
很多人看到范围查询却没触发MRR,往往卡在这几个隐蔽环节:
- 用了覆盖索引:比如
SELECT score FROM student WHERE score BETWEEN 0 AND 59—— 不需要回表,MRR直接被绕过 - 查询只命中极少量行(如
rows估算 ≤ 10):优化器认为排序+缓冲的开销大于随机IO,主动放弃 - 二级索引列基数太低(如
gender只有2个值):即使加了BETWEEN,实际扫描的主键ID仍高度重复或稀疏,排序收益小 -
read_rnd_buffer_size设置过小(默认256KB):缓冲区刚攒几个ID就满了,排序效果弱,优化器倾向不用
验证与调试的关键动作
别猜,直接查执行计划和配置:
- 运行
EXPLAIN SELECT ...,紧盯Extra列是否含Using MRR - 检查当前开关:
SHOW VARIABLES LIKE 'optimizer_switch';,确认输出含mrr=on,mrr_cost_based=off - 临时强制启用(仅测试):
SET optimizer_switch='mrr=on,mrr_cost_based=off';,再跑EXPLAIN - 观察
Handler_read_rnd_next状态变量:启用MRR后该值应明显下降,说明随机回表减少
MRR不是银弹,它的生效依赖于“范围扫描 + 必须回表 + ID乱序 + 缓冲够用”这四者严丝合缝。漏掉任何一个,磁盘就还得东奔西跑。











