MySQL对JOIN做了那些不为人知的优化《死磕MySQL系列 十七》

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MySQL对JOIN做了那些不为人知的优化《死磕MySQL系列 十七》

大家好,我是咔咔 不期速成,日拱一卒


通过上期文章知道了在MySQL中存在三种join的算法,分别为NLJ、BNLJ、BNL,总结来说分为索引嵌套循环连接、缓存块嵌套循环连接、粗暴循环连接。


另外还知道了一个新的概念join_buffer,作用就是把关联表的数据全部读入join_buffer中,然后从join_buffer中一行一行的拿数据去被驱动表中查询。由于是在内存中获取数据,因此效率还是会有所提升。


同时在上期文章中遇到了一个陌生的概念hash_join,在上期中没有详细说明,本期会进行详述。




一、Multi-Range Read优化

在介绍本期主题时先来了解一个知识点Multi-Range Read,主要的作用是尽量让顺序读盘,在任何领域只要是有顺序的都会有一定的性能提升。


比如MySQL的索引,现在你应该知道索引天生具有有序性从而避免服务器对数据再次排序和建立临时表的问题。


接下来使用一个案例来实操一下这个优化是怎么做的


创建join_test1、join_test2两张表

CREATE TABLE `join_test1` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `a` int(11) unsigned NOT NULL,
 `b` int(11) unsigned NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `join_test2` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `a` int(11) unsigned NOT NULL,
 `b` int(11) unsigned NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

给两张表添加一些数据,用于案例演示


drop procedure idata;
delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i<=1000)do
    insert into join_test1 (a,b) values ( 1001-i, i);
    set i=i+1;
  end while;
  set i=1;
  while(i<=1000000)do
    insert into join_test2 (a,b)  values (i, i);
    set i=i+1;
  end while;
end;;
delimiter ;
call idata();

表join_test1的字段a上存在索引的,那么在查询时就会使用该索引。


执行流程大致为获取到字段a所有的值,然后根据a的值一行一行的进行回表到主键索引上获取数据


现在的情况是如果随着a的值递增顺序查询的话,id的值就会变相的为倒叙,虽然看起来是根据主键ID连续倒叙的,但在生产环境下肯定不是连续的,就会造成随机访问,那就肯定会造成性能变差。


为什么说随机访问会影响性能?


MySQL的索引天生具有有序性,同时MySQL也同样借鉴了局部性原理,局部性原理是数据和程序都默认有聚集成群的倾向,在访问到一行数据后,会有极大可能性再次访问到这条数据或这条数据相邻的数据。


现在你应该知道了MySQL在读取数据时并不是只读查询的数据,默认会读取16kb的数据,这个值是根据innodb_page_size决定的。


因此顺序查询是非常快的,是因为不用每次都通过执行器获取数据,而是直接在内存中获取,但若访问变为随机性就会每次通过执行器进行获取数据,所以这才是性能变差的原因。


MRR的作用


说了这么多现在你应该知道了MRR的作用就是把查询变为主键ID的递增查询,对磁盘的读尽可能的接近顺序读,就可以提升性能。


因此,执行语句的执行流程就会变成这样


先根据索a,获取到所有满足条件的数据,并且将主键id的值放入read_rnd_buffer中

在read_rnd_buffer中把id的值进行正序排序

再根据排序后得主键ID值,依次到主键索引上获取数据,并返回结果集

如何开启read_rnd_buffer


read_rnd_buffer的大小是由read_rnd_buffer_size参数控制的,默认值为256kb,但你要知道的是对于MRR的优化在优化器的判断策略中会更倾向于不使用,如果要使用则需要进行配置修改即可。


set optimizer_switch="mrr_cost_based=off"


mrr默认值


image.png


read_rnd_buffer存不下怎么办?


回忆下在上期中提到的join_buffer不够用是怎么处理的,会把上次读取的数据从buffer中清空,再放入剩下的数据,在MySQL中对于存储结果集的buffer内存不够情况下大多数都是这么处理的。


使用了read_rnd_buffer后的SQL执行流程就变成了这样


image.png


explain的结果显示


image.png


注意点


假设现在把查询范围扩大,看一下会有什么变化


image.png


可以看到当把范围扩大至接近全表数据时,会不再使用索引a从而进行了全表扫描,也就无法再使用mrr优化了


因此想要使用MRR进行提升性能是基于两个非常重要的点,一个是在索引上进行范围查询,另一个就是必须能使用上索引,当然这个索引要是范围查询的列


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
SQL 关系型数据库 MySQL
MySQL慢查询优化、索引优化、以及表等优化详解
本文详细介绍了MySQL优化方案,包括索引优化、SQL慢查询优化和数据库表优化,帮助提升数据库性能。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
MySQL慢查询优化、索引优化、以及表等优化详解
|
23天前
|
缓存 监控 关系型数据库
如何优化MySQL查询速度?
如何优化MySQL查询速度?【10月更文挑战第31天】
54 3
|
26天前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
51 1
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:百万级数据统计优化实践
【10月更文挑战第21天】 在处理大规模数据集时,传统的单体数据库解决方案往往力不从心。MySQL和Redis的组合提供了一种高效的解决方案,通过将数据库操作与高速缓存相结合,可以显著提升数据处理的性能。本文将分享一次实际的优化案例,探讨如何利用MySQL和Redis共同实现百万级数据统计的优化。
79 9
|
27天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
150 1
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
61 5
|
2月前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
80 1
|
2月前
|
缓存 关系型数据库 MySQL
一文彻底弄懂MySQL优化之深度分页
【10月更文挑战第24天】本文深入探讨了 MySQL 深度分页的原理、常见问题及优化策略。首先解释了深度分页的概念及其带来的性能和资源问题。接着介绍了基于偏移量(OFFSET)和限制(LIMIT)以及基于游标的分页方法,并分析了它们的优缺点。最后,提出了多种优化策略,包括合理创建索引、优化查询语句和使用数据缓存,帮助提升分页查询的性能和系统稳定性。
128 1
|
28天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
63 0
|
2月前
|
存储 监控 关系型数据库
MySQL并发控制与管理:优化数据库性能的关键
【10月更文挑战第17天】MySQL并发控制与管理:优化数据库性能的关键
181 0