出现Using MRR表示启用了MRR优化,即MySQL将回表的随机IO转为按主键排序后的顺序IO;该标记仅在二级索引扫描且需回表时出现,覆盖索引或结果集过小则不触发,EXPLAIN FORMAT=JSON中的using_mrr字段可进一步确认。

直接看 EXPLAIN 输出的 Extra 列,出现 Using MRR 就表示启用了 MRR 优化;但这个标记只在回表且满足触发条件时才出现,不是所有范围查询都会显示。
如何确认 SQL 执行时实际走了 MRR
关键不是“有没有 MRR 功能”,而是“这条语句是否被优化器选中启用 MRR”。最可靠的方式是执行 EXPLAIN 并检查 Extra 字段:
- 必须是使用**二级索引 + 需要回表**的场景(例如
SELECT *或查询了非索引列),Using MRR才可能出现在Extra中; - 如果走了覆盖索引(
Using index),就不会回表,自然也不触发 MRR,Extra里也不会有Using MRR; - 即使查询类型是
range或ref,若优化器评估成本后认为不划算(比如结果集太小、read_rnd_buffer_size过小或mrr_cost_based=on且代价预估偏高),也会跳过 MRR; - 执行
EXPLAIN FORMAT=JSON可进一步查看"using_mrr": true字段,比文本模式更明确。
为什么 EXPLAIN 显示 Using MRR 却没看到性能提升
MRR 的收益高度依赖底层 I/O 特性与数据分布,不是开了就一定快:
- SSD 上随机 I/O 延迟远低于机械盘,MRR 的顺序化优势会被削弱,甚至因排序开销反而略慢;
- 若查询结果集很小(比如
-
read_rnd_buffer_size设置过小(默认 256KB),导致频繁 flush 排序缓冲区,产生多次小批量顺序读,失去“批量”意义; - 主键物理分布严重碎片化(比如大量
DELETE + INSERT后未OPTIMIZE TABLE),即使按主键排序,磁盘上仍非连续,预读失效。
如何控制 MRR 的开关与行为
MRR 不是独立开关,它由两个系统变量协同控制:
-
mrr=on是前提:用SET SESSION optimizer_switch='mrr=on';启用; -
mrr_cost_based=on(默认)表示优化器按成本估算决定是否启用;设为off则强制走 MRR(仅调试用,生产环境慎用); -
read_rnd_buffer_size直接影响缓冲区容量和排序粒度,建议根据典型查询返回行数调整(如预期主键值占 8 字节/个,256KB ≈ 32K 主键值); - 注意作用域:
SESSION级设置只影响当前连接,GLOBAL级需 SUPER 权限且对已连接会话无效。
容易被忽略的 MRR 触发边界
MRR 不是“范围查询就自动来”,它对索引结构和谓词写法很敏感:
- 联合索引下,只有当查询条件能精确拆解为多个等值点(如
(a,b) IN ((1,100),(2,100),...))时,MRR 才可能激活“Key-Value 拆分”路径; -
BETWEEN或>= / 若落在联合索引的非前导列上(如索引 <code>(a,b),查询WHERE b = 100),无法利用索引有序性,MRR 通常不生效; - 使用
OR拼接多个范围条件(如WHERE a > 10 OR b )可能触发 <code>index_merge,此时 MRR 不参与; - 如果
WHERE中混用函数(如WHERE YEAR(create_time) = 2025),索引失效,MRR 更无从谈起。


















