美文网首页
mysql 索引优化特性之MRR

mysql 索引优化特性之MRR

作者: 尹楷楷 | 来源:发表于2020-11-16 10:48 被阅读0次

MRR针对于辅助索引上的范围查询进行优化,收集辅助索引对应主键rowid。进行排序后回表查询,随机IO转顺序IO

当我们需要对大表(基于辅助索引)进行范围扫描时,会导致产生许多随机/O。而对于普通磁盘来说,随机的性能很差,会遇到瓶颈,在 MySQL 5.6/5.7和MariaDB5.3/5.5/10.0/10.1版本里对这种情况进行了优化,一个新的名词 Multi Range Read(MRR)出现了,优化器会先扫描辅助索引,然后收集每行的主键(rowid ),并对主键进行排序(排序结果存储到read_rnd_buffer),此时就可以用主键顺序访问基表,即用顺序IO代替随机IO。

而MRR的优化在于,并不是每次通过辅助索引读取到数据就回表去取记录,范围扫描(range access)中MySQL将扫描到的数据存入由 read_rnd_buffer_size 变量定义的内存大小中,默认256K。然后对其按照Primary Key(RowID)排序,然后使用排序好的数据进行顺序回表,因为我们知道InnoDB中叶子节点数据是按照PRIMARY KEY(ROWID)进行顺序排列的,所以我们可以认为,如果按照主键的递增顺序查询的话,对磁盘的读比较接近顺序读,能够提升读性能。这对于IO-bound类型的SQL查询语句带来性能极大的提升。

MRR 能够提升性能的核心在于,这条查询语句在索引上做的是一个范围查询(也就是说,这是一个多值查询),可以得到足够多的主键id。这样通过排序以后,再去主键索引查数据,才能体现出“顺序性”的优势。所以MRR优化可用于range,ref,eq_ref类型的查询,工作方式如下图:

MySQL联接查询算法(NLJ、BNL、BKA、HashJoin)

简单说:使用辅助索引进行范围查询时,MRR会收集并排序好符合范围查询条件的rowid。然后通过顺序的rowid去回表查询数据记录。 MRR 通过把「随机磁盘读」,转化为「顺序磁盘读」,从而提高了索引查询的性能。

mysql中mrr相关操作

mysql默认开启MRR优化。但是由优化器决定是否真正使用MRR(mrr=on,mrr_cost_based=on),因为有些时候优化器认为不使用MRR性能会更好!查询MRR的开启状态如下:

SHOW VARIABLES LIKE '%optimizer_switch%'

index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=off,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on

关闭MRR优化,不强制使用MRR

 set optimizer_switch='mrr=off,mrr_cost_based=on';

k_1是sbtest1 表的一个辅助索引,执行计划如下:

EXPLAIN SELECT * from sbtest1 force index(k_1)  where k BETWEEN 1000 and 55555
image.png image.png

再来看开启MRR,并强制使用。可以看到执行计划的Extra列多了Using MRR

 set optimizer_switch='mrr=on,mrr_cost_based=off';
image.png image.png

mrr=on会开启MRR优化功能,mrr_cost_based 则是用来告诉优化器,要不要基于使用 MRR 的成本,考虑使用 MRR 是否值得(cost-based choice),来决定具体的 sql 语句里要不要使用 MRR。很明显,对于只返回一行数据的查询,是没有必要 MRR 的,而如果你把 mrr_cost_based 设为 off,那优化器就会通通使用 MRR。建议这个配置还是设为 on,毕竟优化器在绝大多数情况下都是正确的。另外还有一个配置 read_rnd_buffer_size ,是用来设置用于给 rowid 排序的内存的大小。显然,MRR 在本质上是一种用空间换时间的算法。MySQL 不可能给你无限的内存来进行排序,如果 read_rnd_buffer 满了,就会先把满了的 rowid 排好序去磁盘读取,接着清空,然后再往里面继续放 rowid,直到 read_rnd_buffer 又达到 read_rnd_buffe 配置的上限,如此循环。

另外 MySQL 的其中一个分支 Mariadb 对 MySQL 的 MRR 做了很多优化。

SHOW VARIABLES LIKE '%read_rnd_buffer%' -- 262144 字节 0.25M

注意:MRR 只是针对优化回表查询的速度,当不需要回表访问的时候,MRR就失去意义了(比如覆盖索引)

optimizer_switch可以是全局的,也可以是会话级的。当然,除了调整参数外,数据库也提供了语句级别的开启或关闭MRR,使用方法如下:

EXPLAIN SELECT /*+ MRR(sbtest1)*/ *  from sbtest1 force index(k_1)  where k BETWEEN 1000 and 55555
image.png

相关文章

  • mysql 索引优化特性之MRR

    MRR针对于辅助索引上的范围查询进行优化,收集辅助索引对应主键rowid。进行排序后回表查询,随机IO转顺序IO ...

  • MRR与ICP优化

    mysql5.6对于辅助索引的查询进行了优化 MRR(Multi-Range Read) 优化点 把离散的随机io...

  • Multi-Range Read优化

    1 概述 MySQL Multi-Range Read(MRR)优化主要用于在使用二级索引访问数据时减少随机读。 ...

  • 第三个模块 MySQL-UUID、分词字典、MySQL全文索引

    论mysql5.7.13性能优化之索引优化mysql优化(1)show命令 慢查询日志 explain profi...

  • 第三个模块 让Mysql支持Emoji表情

    让Mysql支持Emoji表情Emoji表情,插入Mysql时失败了!论mysql5.7.13性能优化之索引优化 ...

  • mysql 8.0 关于隐式索引简介

    MySQL 8.0 支持了Invisible Indexes 隐式索引这个特性,可以把某个索引设置为对优化器不可见...

  • 数据库存储原理特性索引优化

    说一下mysql数据库存储的原理? 事务的特性? 数据库索引 数据库怎么优化查询效率? 数据库优化方案 优化索引、...

  • mysql 索引优化特性之索引下推

    索引下推优化默认开启,索引下推 和联合索引有密切的关系,它让组合索引里的范围条件变得有意义 查询开启状态 我们可以...

  • mysql优化概述

    一:mysql优化概述:设计角度:存储引擎的选择,字段类型选择,范式。利用mysql自身的特性:索引,查询缓存,分...

  • mysql 隐式索引

    定义 MySQL 支持不可见索引;即优化器不使用的索引。该特性适用于主键以外的索引(显式或隐式)。 控制索引可见性...

网友评论

      本文标题:mysql 索引优化特性之MRR

      本文链接:https://www.haomeiwen.com/subject/ujpabktx.html