使用辅助索引的范围扫描读取行可能会导致大量随机磁盘访问,以访问大型表中的基础表数据,而这些数据不在存储引擎的缓存中。使用磁盘扫描多范围读取(MRR)优化,MySQL 尝试减少范围扫描的随机磁盘访问次数。首先,MySQL 扫描索引,收集相关行的键,然后对键进行排序,最后按照主键的顺序从基础表中检索行。
多范围读取优化提供以下优点:
-
MRR 使数据行可以按顺序访问,而不是随机访问,基于索引元组的顺序。服务器获取满足查询条件的一组索引元组,按照数据行 ID 顺序对其进行排序,然后使用排序后的元组按顺序访问数据行。这使得数据访问更加高效和经济。
-
MRR 使批处理请求可以访问数据行,例如范围索引扫描和等值连接操作,使用索引访问数据行。MRR 遍历索引范围序列,获取合格的索引元组,然后使用这些结果访问对应的数据行。无需获取所有索引元组后再开始读取数据行。
MRR 优化不支持虚拟生成列上的辅助索引。InnoDB
支持虚拟生成列上的辅助索引。
以下场景说明了 MRR 优化何时可以发挥优势:
场景 A:MRR 可用于 InnoDB
和 MyISAM
表的索引范围扫描和等值连接操作。
-
部分索引元组被累积到缓冲区中。
-
缓冲区中的元组按照数据行 ID 顺序排序。
-
数据行按照排序后的索引元组顺序访问。
场景 B:MRR 可用于 NDB
表的多范围索引扫描或等值连接操作。
-
部分范围,可能是单键范围,被累积到中央节点的缓冲区中。
-
范围被发送到执行节点,以访问数据行。
-
访问的行被打包到包中并发送回中央节点。
-
收到的包中的数据行被放入缓冲区中。
-
数据行从缓冲区中读取。
当使用 MRR 时,EXPLAIN
语句的 Extra
列显示 Using MRR
。
InnoDB
和 MyISAM
不使用 MRR,如果不需要访问完整的表行来产生查询结果。这是在索引元组中可以完全产生结果的情况下(通过 covering index);MRR 不提供任何优势。
两个 optimizer_switch
系统变量标志提供了对 MRR 优化的接口。mrr
标志控制是否启用 MRR 优化。如果 mrr
启用(on
),则 mrr_cost_based
标志控制优化器是否尝试基于成本的选择,使用或不使用 MRR(on
),或总是使用 MRR(off
)。默认情况下,mrr
是 on
,mrr_cost_based
是 on
。请参阅 第 10.9.2 节,“可切换优化”。
对于 MRR,存储引擎使用 read_rnd_buffer_size
系统变量的值作为其缓冲区大小的指导方针。引擎使用高达 read_rnd_buffer_size
字节的缓冲区,并确定单个传递中要处理的范围数。