当表很大且未存储在存储引擎的缓存中时,使用二级索引上的范围扫描读取行可能会导致对基表的许多随机磁盘访问。通过磁盘扫描多范围读取 (MRR) 优化,MySQL 尝试通过首先仅扫描索引并收集相关行的键来减少范围扫描的随机磁盘访问次数。然后对键进行排序,最后使用主键的顺序从基表中检索行。Disk-sweep MRR 的动机是减少随机磁盘访问的次数,而是实现对基表数据的更顺序扫描。
多范围读取优化提供以下优势:
MRR 使数据行能够基于索引元组按顺序而不是随机顺序访问。服务器获取一组满足查询条件的索引元组,按照数据行ID顺序排序,使用排序后的元组按顺序检索数据行。这使数据访问更加高效且成本更低。
MRR 支持对需要通过索引元组访问数据行的操作的键访问请求进行批处理,例如范围索引扫描和使用连接属性索引的等值连接。MRR 遍历一系列索引范围以获得合格的索引元组。随着这些结果的累积,它们将用于访问相应的数据行。在开始读取数据行之前,不需要获取所有索引元组。
在虚拟生成列上创建的二级索引不支持 MRR 优化。
InnoDB
支持虚拟生成列的二级索引。
以下场景说明了 MRR 优化何时有利:
场景 A:MRR 可用于索引范围扫描InnoDB
和
MyISAM
等连接操作的表。
一部分索引元组累积在缓冲区中。
缓冲区中的元组按其数据行 ID 排序。
根据排序的索引元组序列访问数据行。
场景 B:MRR 可用于
NDB
多范围索引扫描的表或按属性执行等值连接时。
范围的一部分(可能是单键范围)累积在提交查询的中央节点上的缓冲区中。
范围被发送到访问数据行的执行节点。
访问的行被打包成包并发送回中央节点。
接收到的带有数据行的包被放置在一个缓冲区中。
从缓冲区读取数据行。
使用 MRR 时Extra
,输出中的列
EXPLAIN
显示
Using MRR
。
InnoDB
MyISAM
如果不需要访问完整的表行来生成查询结果,则不要使用 MRR。如果结果可以完全基于索引元组中的信息(通过覆盖索引)产生,就是这种情况;MRR 没有任何好处。
两个optimizer_switch
系统变量标志提供了使用 MRR 优化的接口。该mrr
标志控制是否启用 MRR。如果
mrr
启用 ( on
),则该
mrr_cost_based
标志控制优化器是尝试在使用和不使用 MRR ( on
) 之间做出基于成本的选择,还是尽可能使用 MRR ( off
)。默认情况下,mrr
是
on
和
mrr_cost_based
是
on
。请参阅
第 8.9.2 节,“可切换优化”。
对于 MRR,存储引擎使用
read_rnd_buffer_size
系统变量的值作为它可以为其缓冲区分配多少内存的指导。引擎最多使用
read_rnd_buffer_size
字节并确定要在单次传递中处理的范围数。