揭秘MySQL范围查询优化:MRR(多范围读取优化)如何将随机IO转化为顺序IO

文摘   2024-09-26 20:15   广东  

MySQL中MRR(Multi-Range Read)优化是一种重要的查询优化技术,其在处理包含多个范围条件的查询时,能够显著提升查询效率。

  • 一、MRR优化概述

  • 二、MRR优化的背景

  • 三、MRR优化的原理

  • 四、MRR优化的优势

  • 五、磁盘预读机制

  • 六、局部性原理

  • 七、使用场景、条件与监控

  • 八、SQL案例解读

一、MRR优化概述

MRR,全称Multi-Range Read Optimization,直译为多范围读取优化,是MySQL中一种用于提高索引查询性能的技术。MRR通过减少随机磁盘访问次数,将随机IO转换为顺序IO,从而提高数据读取的效率。它特别适用于包含范围条件(如BETWEEN、<、>等)的查询,以及需要通过辅助索引访问表数据的场景。

二、MRR优化的背景

在InnoDB中表数据是通过聚集索引组织的。当基于辅助索引的范围查询时,需要先通过辅助索引找到对应的主键值,再通过主键值回表查询完整的行数据。这种回表会产生大量的随机磁盘I/O,尤其是在处理大表时,随机I/O的性能瓶颈尤为明显。MRR优化正是为了解决这一问题提出。

三、MRR优化的原理

MRR优化的核心思想是将多个范围查询中的随机磁盘I/O转换为顺序磁盘I/O,从而提高查询性能。

  1. 扫描辅助索引并收集主键值

  • 当执行一个包含范围条件的查询时,MySQL优化器首先会扫描辅助索引,找到满足条件的一系列索引元组。
  • 对于每个索引元组,MySQL会收集其对应的主键值(rowid)。
  • 对主键值进行排序

    • 收集到的主键值会被放入一个内存缓冲区(read_rnd_buffer)中。
    • 当缓冲区满或查询结束时,MySQL会对缓冲区中的主键值进行排序。排序的目的是为了将随机访问转换为顺序访问。
  • 顺序访问基表

    • 排序后的主键值将按照顺序被用来访问基表,检索出完整的数据行。
    • 由于主键值是有序的,因此访问基表时产生的磁盘I/O也变为顺序I/O,从而提高了读取效率。
  • 利用磁盘预读和缓存机制

    • MRR优化还充分利用了磁盘的预读机制。当请求读取某一页数据时,磁盘会预测并提前读取相邻的几页数据到内存中。
    • 由于MRR将随机访问转换为顺序访问,磁盘预读机制能够更好地发挥作用,减少磁盘寻道时间和旋转延迟。
    • 同时,顺序访问也提高了缓存的命中率,因为连续访问的数据页更有可能在缓存中找到。

      四、MRR优化的优势

      • 提高查询性能:通过减少随机磁盘I/O次数和提高缓存命中率,MRR优化能够显著提高查询性能。
      • 减少I/O成本:顺序I/O比随机I/O具有更低的成本,因为顺序I/O可以更有效地利用磁盘带宽和缓存资源。
      • 适用于多种查询类型:MRR优化不仅适用于范围查询(如BETWEEN、<、>等),还适用于等值连接(equi-join)等需要回表访问的场景。

      五、磁盘预读机制

      MRR优化充分利用了磁盘预读机制。当客户端请求读取某一页数据时,磁盘预读功能会预测并提前读取相邻的几页数据到内存缓冲区中。由于MRR将随机访问转换为顺序访问,磁盘预读机制能够更好地发挥作用,减少磁盘寻道时间和旋转延迟,进一步提升读取效率。

      六、局部性原理

      局部性原理是MRR优化的另一个理论基础。时间局部性表明,如果某个数据项被访问,那么在不久的将来它可能再次被访问;空间局部性表明,一旦某个数据项被访问,那么其附近的数据项也可能很快被访问。MRR通过顺序访问数据,使得数据访问更加符合局部性原理,从而提高了缓存命中率,减少了磁盘访问次数。

      七、使用场景、条件与监控

      MRR优化适用于基于范围扫描和等值连接的操作中尤为有效。但是,并非所有查询都能从MRR优化中受益。如,当查询完全基于索引元组中的信息(即使用覆盖索引)时,MRR优化就没有必要,因为此时无需回表访问基表数据。

      此外,MySQL默认开启MRR优化,但是否真正使用MRR由优化器决定。优化器会根据查询的成本(如IO成本、CPU成本等)来决定是否采用MRR优化。用户可以通过调整optimizer_switch系统变量中的mrrmrr_cost_based标志来控制MRR优化的使用。

      1. 配置参数

      • optimizer_switch:包含mrr和mrr_cost_based两个选项,分别用于控制是否启用MRR优化以及是否基于成本决定是否使用MRR。
      • read_rnd_buffer_size:设置用于给rowid排序的内存缓冲区的大小。这个参数的大小会影响MRR优化的效果,需要根据实际情况进行调整。

      2. 监控方法

      • 使用EXPLAIN语句查看查询的执行计划。如果查询使用了MRR优化,EXPLAIN的输出会在Extra列中显示Using MRR。
      • 监控查询的响应时间和I/O开销。通过比较开启和关闭MRR优化时的查询性能,可以评估MRR优化的效果。

      八、SQL案例解读

      一个orders的表结构:

      CREATE TABLE orders (
          id INT AUTO_INCREMENT PRIMARY KEY,
          customer_id INT NOT NULL,
          order_date DATE NOT NULL,
          total_amount DECIMAL(102NOT NULL,
          INDEX idx_customer_date (customer_id, order_date)
      ENGINE=InnoDB;

      表中,customer_idorder_date上有一个联合索引idx_customer_date。想要查询某个特定客户在指定日期范围内的所有订单,SQL语句:

      SELECT * FROM orders WHERE customer_id = 123 AND order_date BETWEEN '2024-09-25' AND '2024-09-26';
      1. 扫描辅助索引

      • MySQL首先会利用辅助索引idx_customer_date来定位满足customer_id = 123order_date BETWEEN '20234-09-25' AND '2024-09-26'条件的索引元组。
      • 这些索引元组包含了customer_idorder_date以及对应的主键值
    1. 收集并排序主键值

      • MySQL会收集这些索引元组对应的主键值,并将它们放入一个内存缓冲区(read_rnd_buffer)中。
      • 当缓冲区满或查询结束时,MySQL会对这些主键值进行排序。排序的目的是为了后续的顺序访问基表。
    2. 顺序访问基表

      • 使用排序后的主键值,MySQL将顺序访问orders表的基表部分,检索出完整的订单数据行。
      • 由于主键值是有序的,因此访问基表时产生的磁盘I/O变为顺序I/O。
    3. 利用磁盘预读和缓存机制

      • 在顺序访问基表的过程中,磁盘预读机制会预测并提前读取相邻的数据页到内存中。
      • 这有助于减少磁盘寻道时间和旋转延迟,并提高缓存命中率。
    4. 查询性能提升

      • 相比没有MRR优化的情况,使用MRR可以显著减少随机磁盘I/O的次数,从而提高查询性能。
      • 特别是在处理大表时,MRR优化的效果更加明显。

      太强 ! SpringBoot中出入参增强的5种方法 : 加解密、脱敏、格式转换、时间时区处理

      太强 ! SpringBoot中优化if-else语句的七种绝佳方法实战

      SpringBoot使用EasyExcel并行导出多个excel文件并压缩zip下载
      提升编程效率的利器: Google Guava库中双向映射BitMap
      从MySQL行格式原理看:为什么开发规范中不推荐NULL?数据是如何在磁盘上存储的?
      SpringBoot中使用Jackson实现自定义序列化和反序列化控制的5种方式总结
      提升编程效率的利器: Google Guava库之RateLimiter优雅限流
      深入JVM逃逸分析原理:且看其如何提高程序性能和内存利用率
      必知必会!MySQL索引下推:原理与实战

      深入解析JVM内存分配优化技术:TLAB

      SpringBoot中基于JWT的双token(access_token+refresh_token)授权和续期方案
      SpringBoot中基于JWT的单token授权和续期方案
      SpringBoot中Token登录授权、续期和主动终止的方案(Redis+Token)
      微服务中token鉴权设计的4种方式总结
      提升编程效率的API利器:精通Google Guava库区间范围映射RangeMap
      SpringBoot中Jackson控制序列化和反序列化的注解和扩展点总结【收藏版】

      SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载

      SpringBoot中基于XXL-JOB实现大量数据灵活控制的分片处理方案


      关注『 码到三十五 』,日有所获
                           点赞 和 在看 就是最大的支持

      码到三十五
      主要分享正经的开发技术(原理,架构,实践,源码等),以输出驱动输入;当然偶尔会穿插点生活琐碎,顺便吃个瓜,目的嘛,搞点精准流量,看能不能发发广告。
       最新文章