MySQL关联查询如何优化

好久不见,关于这篇文章,我也是想了很久,还是决定写一篇文章,有很多同学问过 mysql 相关的问题,其实关联查询如何优化,首先我们要知道关联查询的原理是什么?

左连接 left join

SELECT 字段列表
FROMA表 
LEFT JOIN B表
ON 关联条件
WHERE 等其他子句

两表关联,以 left 左边的表为主表进行查询,除了返回满足连接条件的行以外,还返回左表中不满足条件的行。
如图所示:A 表是主表(驱动表),B 表是从表(被驱动表),颜色区域即所得结果集,结果集中返回匹配的行(交集),也返回 A 表中不匹配的行,不匹配字段用 NULL 表示。
在这里插入图片描述

右连接 right join

SELECT 字段列表
FROMA表 
RIGHT JOIN B表
ON 关联条件
WHERE 等其他子句

两表关联,以 right 右边的表为主表进行查询,除了返回满足连接条件的行以外,还返回右表中不满足条件的行。
如图所示:B 表是主表(驱动表),A 表是从表(被驱动表),颜色区域即所得结果集,结果集中返回匹配的行(交集),也返回 B 表中不匹配的行,不匹配字段用 NULL 表示。(同 left join,只不过主表位置不同)
在这里插入图片描述

内连接 inner join

SELECT 字段列表
FROM A表 
INNER JOIN B表
ON 关联条件
WHERE 等其他子句;

两表关联,返回符合 where 条件的结果集,即是 A 表 结果集,也是 B 表结果集,内联查询,没有左右主表之分,以哪张表为驱动表,取决于 MySQL service 层的优化器自己决定。
如图所示:
在这里插入图片描述

关联查询原理

前面讲解了连接查询的几种方式,现在谈谈 MySQL 底层是支持这几种连接查询的。
关联查询中涉及到多表的的查询,根据驱动类型分为驱动表和被驱动表,驱动表就是主表,被驱动表就是从表。
那么 MySQL 是如何进行join查询的呢?

1.Simple Nested-Loop Join (简单嵌套循环连接)

是从驱动表 A 中取出一条数据,遍历表 B,将匹配到的数据放到result,以此类推, 如下图所示:
在这里插入图片描述
比如驱动表A有10条,被驱动表B有100条,那么扫描次数是A+A*B, 每一次扫描其实就是从硬盘中读取数据加载到内存中,也就是一次IO,而IO是最大的瓶颈,所以效率低下,开销如下表:

开销统计简单嵌套循环连接
驱动表扫描次数1
被驱动表扫描次数A
读取记录数A+B*A
JOIN比较次数B*A
回表读取记录次数0

当然 MySQL 肯定不会这么粗暴的去进行表的连接,所以就出现了后面的两种对 Nested-Loop Join 优化算法。

2.Block Nested-Loop Join (块嵌套循环连接)

块嵌套循环连接是对上面一种算法的优化,简单嵌套是去驱动表中获取数据去匹配,和磁盘 IO 交互太多了,那么能否以一种批量的方式进行优化呢?mybatis 批量插入批量查询也是这个道理。而这种算法就是借鉴了这样的思想。
不再是逐条获取驱动表的数据,而是一块一块的获取,引入了 join buffer 缓冲区,将驱动表join相关的部分数据列、缓存到join buffer中,然后全表扫描被驱动表,被驱动表的每一条记录一次性和join buffer中的所有驱动表记录进行匹配(内存中操作),将简单嵌套循环中的多次比较合并成一次,降低了被驱动表的访问频率。整体如下图所示:
在这里插入图片描述
需要注意的是:从驱动表中缓存的列不仅仅是关联的的列,select 后面的列也会缓存起来。因此,为了能让 join buffer 缓存更多的数据,我们的 SQL 尽量不要 select *, 而是 select 用到的字段。
开销如下表:

开销统计块嵌套循环连接
驱动表扫描次数1
被驱动表扫描次数A*used_column_size/join_buffer_size+1
读取记录数A+B*(A*used_column_size/join_buffer_size)
JOIN比较次数B*A
回表读取记录次数0

join buffer的大小是可以设置的,默认情况下 join_buffer_size=256k。
join_buffer_size 的最大值在32位操作系统可以申请4G,而在64位操作系统下可以申请大于4G的 Join Buffer 空间(64位Windows除外,其大值会被截断为4GB并发出警告)。

3.Index Nested-Loop Join (索引嵌套循环连接)

索引嵌套循环连接(Index Nested-Loop Join)就是效率最高的,前提条件是被驱动表的关联字段建立了索引。通过驱动表匹配条件直接与被驱动表的索引进行匹配,避免和内存表的每条记录去进行比较,这样极大的减少了对内存表的匹配次数。如下图所示:
在这里插入图片描述
因为索引查询的成本基本一样,为了降低开销,驱动表是小表更加合适。所以我们常说把小表当作主表是有原因的。
开销如下表:

开销统计索引嵌套循环连接
驱动表扫描次数1
被驱动表扫描次数0
读取记录数A+B(match)
JOIN比较次数A*Index(Height)
回表读取记录次数B(match)(if possible)

如果被驱动表加索引,效率是非常高的,但如果索引不是主键索引,所以还得进行一次回表查询。相比,被驱动表的索引是主键索引,效率会更高。

块嵌套循环连接:对于被连接的数据子集较小的情况下,它是个较好的选择。
Hash Join: 是做大数据集连接时的常用方式,优化器使用两个表中较小(相对较小)的表利用 Join Key 在内存中建立散列值,然后扫描较大的表并探测散列值,找出与 Hash 表匹配的行。它能够很好的工作于没有索引的大表和并行查询的环境中,并提供最好的性能。Hash Join 只能应用于等值连接,这是由 Hash 的特点决定的。
在这里插入图片描述

总结:优化建议

前面讲了原理,从原理出发,讲一下优化的建议

  1. 被驱动表的连接字段建立索引,因为建立索引的查询方式是效率最高的。
  2. left join 或者 right join 这种外连接的情况,要保证小表(小结果集)作为驱动表,大表(大结果集)作为被驱动表,这样性能更好。
  3. 在查询字段的话,要避免写出 select * ,而是根据业务需要,需要查询出来的 select 出来就行,因为这些字段也会加入到 join buffer 中,减少额外的内存消耗。
  4. 能够直接多表关联的尽量直接关联,不用子查询,因为子查询的效率更加低。
  5. 在 sql 的查询计划的 extra 中,尽量避免出现 Using join buffer,有这个表示使用了块嵌套循环连接算法,尽量通过索引去解决。
  6. 尽量避免超过 3 张表以上的关联查询。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/756040.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

携程Kar98k/hotelUuidKey算法分析

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 这里只是我分析的分析过程,以及一些重要点的记录…

【ARM】DS中Coretex-M处理器的常用寄存器介绍

【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 了解ArmDS中Coretex-M处理器的常用寄存器的名称及作用。 2、 问题场景 在对Coretex-M处理器进行开发时,了解常用寄存器的名称及作用,可以: 编写正确的程序: 寄存器是程序员用…

UE4_AI_行为树_行为树快速入门指南

声明:学习笔记。 在 行为树快速入门指南 中,你将学会如何创建一个敌方AI,该AI看到玩家后会做出反应并展开追逐。当玩家离开视线后,AI将在几秒钟后(这可根据你的需求进行调整)放弃追逐,并在场景中…

使用 Postman 批量发送请求的最佳实践

背景 最近写了几个接口: 获取 books 的接口获取 likes 的接口获取 collections 的接口 但是我还是不放心,因为这些接口到底稳不稳定呢?上线后有没有隐患呢?所以我想做一个批量发送接口模拟~ 但是想要做到批量发送接口&#xf…

考研数学|《基础660》太难了!哪本习题集更适合打基础?

对于基础阶段的学习者来说,推荐使用汤家凤老师的《1800题》。这本题集包含了大量的数学题目,覆盖了考研数学的各个知识点和难度层次。题目设计全面,有助于系统地复习和巩固数学知识。 《1800题》提供了详细的解题思路和答案解析,…

oops-framework框架 之 启动流程(三)

引擎: CocosCreator 3.8.0 环境: Mac Gitee: oops-game-kit 回顾 上篇博客中我们通过 oops-game-kit 模版构建了基础的项目,另外讲解了下assets目录结构和游戏配置文件的基本使用相关,详情内容可参考: oops-framewo…

DevOps工作流程之一:Apipost

随着互联网行业的不断发展,为了提高工作效率,加快软件的交付流程,越来越多企业的选择DevOps工作流程。DevOps旨在通过自动化流程和改善协作,实现软件开发、测试和交付的一体化,从而提高软件交付的质量和速度。而Apipos…

测试面试必备:HTTP请求和响应详解!

一次完整的HTTP请求过程从TCP三次握手建立连接成功后开始,客户端按照指定的格式开始向服务端发送HTTP请求,服务端接收请求后,解析HTTP请求,处理完业务逻辑,最后返回一个HTTP的响应给客户端,HTTP的响应内容同…

wireshark 使用实践

1、打开wireshark软件,选择网卡,开始抓包 2、打开浏览器,访问一个http网站:这里我用 【邵武市博物馆】明弘治十一年(1498)铜钟_文物资源_福建省文 测试,因为它是http的不是https,方…

【OpenWRT】x86平台安装原版OpenWRT

在当今高度互联的数字化时代,网络设备已经成为我们日常生活和工作中不可或缺的一部分。为了满足不同用户对网络功能的个性化需求,开源社区涌现出了诸多优秀的项目,其中 OpenWrt 便是其中之一。 OpenWrt 是一款专注于为嵌入式设备提供定制化、…

【Leetcode-102.二叉树的层序遍历】

题目详情: 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]]示例…

GPT实战系列-智谱GLM-4的模型调用

GPT实战系列-智谱GLM-4的模型调用 GPT专栏文章: GPT实战系列-实战Qwen通义千问在Cuda 1224G部署方案_通义千问 ptuning-CSDN博客 GPT实战系列-ChatGLM3本地部署CUDA111080Ti显卡24G实战方案 GPT实战系列-Baichuan2本地化部署实战方案 GPT实战系列-让CodeGeeX2帮…

【Java刷题篇】滑动窗口

文章目录 📃滑动窗口📜基本概念📜核心思路 ✍最大连续1的个数 III✍水果成篮 📃滑动窗口 📜基本概念 滑动窗口是一种基于双指针的一种思想,两个指针指向的元素之间形成一个窗口。 分类:窗口有…

【物联网】Modbus 协议及应用

Modbus 协议简介 QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集,这里就我们的实际项目经验分享Modbus协议 简介 Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太…

libVLC windows开发环境搭建

1.简介 LibVLC是一个强大的开源库,它构成了VLC媒体播放器的核心部分。 LibVLC提供了一系列的功能接口,使得VLC能够处理流媒体的接入、音频和视频输出、插件管理以及线程系统等核心任务。 跨平台性:VLC作为一个跨平台的多媒体播放器&#x…

Java instanceof

目录 简介 示例 注意事项 应用场景 简介 instanceof 是 Java 的保留关键字也称为类型比较运算符,因为它将实例与类型进行比较它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型instanceof是Java中的二元运算符&#xff0c…

海外代理IP在跨境电商中的五大应用场景

在我国跨境电商的发展中,海外代理IP的应用日益广泛,它不仅帮助商家成功打入国际市场,还为他们在多变的全球电商竞争中保持优势。下面是海外代理IP在跨境电商中五个关键的应用场景。 1、精准的市场分析 了解目标市场的消费者行为、产品趋势以…

[蓝桥杯 2023 省 B] 飞机降落(暴搜DFS+贪心)

总结:为什么你看到题想不出来怎么写呢,我想不到这道题还会用到dfs的思想,顶多能知道可能会有贪心,还是得多做题。 这道题让我想起来导弹拦截和借教室,记得有空做做!!不要研究难题,把…

打造专属云存储:私有Docker Registry全面解读与实战部署

在容器技术大行其道的今天,Docker Registry作为容器镜像的中央仓库,扮演着至关重要的角色。当公开的官方镜像库无法满足企业对安全性、可控性及定制化的需求时,搭建私有Docker Registry就显得尤为必要。本文旨在深入剖析私有Docker Registry的…

题目15—三数之和

题目来源于LeetCode 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重…