必须组合验证:执行EXPLAIN FORMAT=JSON查"using_mrr": true,观察Extra是否含Using MRR或Using index condition; Using MRR,再结合sys.schema_table_statistics对比rnd_next与rnd_pos次数变化,才能确认MRR是否真实生效。
EXPLAIN里没出现Using MRR,不代表MRR没生效;真正起效的前提是:走二级索引 + 必须回表 + 主键值物理分布离散。
不能只看EXPLAIN输出的Extra列是否含Using MRR——它可能被隐藏或跳过。必须组合验证:
EXPLAIN FORMAT=JSON,检查"mrr": true和"mrr_cost": xxx字段是否存在且为正数Extra列:出现Using index condition; Using MRR说明ICP和MRR同时启用;只有Using index condition而无MRR,大概率是read_rnd_buffer_size太小或预估行数低于阈值(默认约10行)SELECT * FROM sys.schema_table_statistics WHERE table_name = 'your_table'对比rnd_next(随机读)和rnd_pos(顺序读)次数变化,比单纯看执行时间更反映MRR真实作用MRR不是所有范围查询都管用,它只在满足“二级索引扫描 → 回表 → 主键离散”三要素时才被优化器考虑:
WHERE status IN (1,2,3)、WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31' ORDER BY id LIMIT 100、WHERE category = 'A' AND price > 100(联合索引最左匹配后带范围)SELECT id, name FROM t WHERE status = 1(覆盖索引,无需回表)、SELECT * FROM t WHERE id > 1000(主键扫描,无二级索引参与)、WHERE JSON_CONTAINS(data, '"abc"')(虚拟列索引不支持MRR)read_rnd_buffer_size就一定更快?不一定,这个参数是一把双刃剑:
TEXT列),排序开销可能反超IO节省SET SESSION read_rnd_buffer_size = 4194304(4M),再结合sys.schema_table_statistics看rnd_next是否明显下降read_rnd_buffer_size是会话级变量,改完必须在同session里跑EXPLAIN或真实查询才能验证效果optimizer_switch里mrr和mrr_cost_based怎么配?这两个开关控制MRR是否可选以及是否由成本驱动:
mrr=on是前提(MySQL 5.7默认开启),否则MRR根本不可用mrr_cost_based=on(默认)表示优化器按成本估算决定是否启用MRR;设为off则强制启用,但容易在小结果集或宽索引场景下适得其反SELECT @@optimizer_switch查看当前值;临时关闭MRR对比性能,可用SELECT /*+ NO_MRR(t) */ ...(MySQL 8.0.20+才支持,5.7不适用)最容易被忽略的一点:启用MRR后EXPLAIN显示的rows可能突然变大——这不是变慢了,而是优化器在展示“排序前”的索引扫描行数,不是最终输出量。别因此误判优化失败。