mysql 使用join进行多表关联查询

join类型

在一些报表统计或数据展示时候需要提取的数据分布在多个表中,这个时候需要进行join连表操作。join将两个或多个表当成不同的数据集合,然后进行集合取交集运算。比如有订单Order表记录用户id,如果像查询订单对应的用户信息,可以将Order和User表进行关联。

根据join结果集计算方式不同,join大致分为两种主要类型:

内连接

内连接(inner join)也称为等值连接,是最常用的Join方式。它只返回两个表中匹配的行,即两个表中具有相同值的列的行。比如 from order o inner join user u on o.uid=u.uid。

外连接

外连接分两种,左外连接和右外连接。两个区别于内连接地方是不仅包含两个表等值情况,返回左表中的所有行以及右表中与左表匹配的行。如果右表中没有匹配的行,则返回NULL。

如from order o left join user u on o.uid=u.uid。order.uid即使在user表不存在也会返回订单记录,只不过对应的用户信息为null。

右连接同理以右表数据为主返回右表所有数据。

还有一种全外连接,没有关联条件,查找两个表之间的所有关联和不关联的记录,无论它们是否有匹配条件。这种应该不常用,只有数据对比时候可能会用。

join原理

mysql在表join查询时候,使用嵌套循环方式(nested-loop algorithm)进行数据匹配。就是拿驱动表每一条和被驱动表所有数据依次进行匹配。这也很好理解。两个关联表相当于两个集合,然后求两个集合的交集。就是从一个集合依次拿出所有和另一个进行比较是否相等(是交集)。假如有t1、t2、t3三个表进行关联,t1上有range范围筛选,t1和t2关联有ref类型索引关联,执行过程大概这样

for each row in t1匹配范围数据 {for each row in t2匹配索引值 {for each row in t3 {t3满足连接条件记录}}
}

这样假设表A有M行记录,表B有N行记录。则需要M乘N次比较取交集。表B被扫描M*N次。这些都是磁盘全表扫描。显然如果M和N都比较大的时候会比较慢。

上面看到嵌套循环,外循环每行记录都会导致内循环多次执行。这里注意多表关联时候不是先计算前两个的关联结果然后结果再和后面的表进行关联。比如上面例子,不会有t1和t2的临时连接结果集。

Block Nested-Loop Join Algorithm

为了提高join的效率,mysql在嵌套循环比对时候进行了一定的修改优化。使用一个变种块嵌套循环(Block Nested-Loop Join Algorithm)。什么意思呢?这次我读取驱动表的时候不是每次读取一条了,我读取多条,存放到一个join buffer 块里。然后这样每次多条和被驱动表的数据进行比较,这样就将原来的多次磁盘读取比较转移到了内存比较。这样被驱动表全表扫描次数变成了:(M/buffer rows)*N。

一次读取的行数(buffer rows),由每行需要的数据大小和join_buffer_size大小两个因素决定。

join_buffer_size的大小默认是256KB

mysql> SELECT @@join_buffer_size;
+--------------------+
| @@join_buffer_size |
+--------------------+
|             262144 |
+--------------------+

从上面的计算公式不难看出,驱动表的行数越少,join_buffer_size越大,扫描被驱动表的次数越少。这也是为什么要使用小表驱动大表的原因。如果驱动表join数据可以一次放到join_buffer_size中则被驱动表只需要一次全表扫描。如果不能驱动表会被分成多次读取到join_buffer_size中,join_buffer_size会循环使用。

join buffer有以下几个特点:

1、当执行计划的type类型是ALL、index或range的时候会使用join buffer。

2、如果一个查询中有多个表进行连接操作, Join Buffer 只会为非常量表分配内存空间,即使这个表的类型是 ALL 或者 index。

3、连接操作的 Join Buffer 中只存储连接所需的列,而不是整个行。

4、一个join分配一个join buffer,如果一个查询有多个join可能会使用多个join buffer。

5、join buffer的分配在join执行前完成,查询结束后立即释放。

如果使用了join buffer,一般在explain的Extra列会有Using join buffer (Block Nested Loop)信息。

Index Nested-Loop Join

上面说的使用Block Nested-Loop Join算法,相对最初的嵌套循环使用join buffer提高了匹配的效率。但是当表数据很大时,仍然不太理想。在Block Nested-Loop Join算法中执行计划type最好是range。还有更好的ref和eq_ref没有说。也就是当join的列是索引列时。

注意这里说的索引列是指被驱动表,因为驱动表总是要进行一次全表扫描。但是这个时候去被驱动表找数据就不是全表扫描了,因为有索引,是直接在索引树上进行查找这就快多了。

在常规业务开发(非高并发)进行表join操作是非常常见的,在表连接时候尽量使用小表驱动大表,这里的小表是指条件过滤后参加join条件的数据。连接时在被驱动表连接字段上创建索引,也就是使用Index Nested-Loop Join。

join优化

Batched Key Access Joins(BKA)

Batched Key Access Joins从名字上也能看出来大致意思。key是索引意思,是对Index Nested-Loop Join的查询优化。 BKA要借助于MRR,先来说下MRR。

Multi-Range Read

当在某个辅助索引上进行范围查找时,通常在回表查询的过程中会发生大量的随机读。

比如下面的语句

select * from user where uname like '曹%';

uname列上建有索引,可以从uname索引上获取主键值,然后再回表根据主键逐条从聚簇索引上查询行数据。这个时候获取的主键是无序的,会造成大量的随机读。MRR(Multi-Range Read)优化就是为了解决这种场景,

MRR处理过程是在根据索引获取到主键后不是立即进行回表查询,而是先将主键值放入到一个read_rnd_buffer中,然后对其进行排序,最后再有序的去聚簇索引检索行数据。如果对应主键索引值足够密集,这样可以大大减少随机读。

read_rnd_buffer的大小由read_rnd_buffer_size参数来进行控制,默认大小是256kb。另外开启MMR需要在optimizer_switch中设置mrr=on。默认值是on。另外还有一个相关的参数mrr_cost_based,如果这个参数设置为off表示符合条件就使用mrr,如果为on则优化器会基于成本进行考虑是否使用mrr。该值默认是on 。

如果使用到了mrr,在explain的Extra列一般会显示:Using index condition; Using MRR。

看完了上面的MRR,这里回到使用索引join连表查询其实也存在上面的问题。回想Index Nested-Loop Join的查询执行过程,是每次一行行的去驱动表中去找数据,每次驱动表只被匹配一个值。这里Batched Key Access Joins就结合了Block Nested-Loop Join和MRR两个的优点,执行过程大致如下:

1、批量取驱动表的关联字段放入join buffer中

2、将join buffer中的关联列值,批量的发送给引擎在被驱动表上通过MRR以最优的方式进行索引树搜索匹配,获取到对应的主键(rowId)。

3、按检索到的rowId进行排序,顺序从被驱动表上获取关联数据。

BKA是对Index Nested-Loop Join的优化,被驱动表上要有对应的索引。并且被驱动表上会发生回表查询的情况。

开启BKA首先需要开启MRR,需要进行以下设置

mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

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

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

相关文章

uniapp中使用EelementPlus

uniapp的强大是非常震撼的,一套代码可以编写到十几个平台。这个可以在官网上进行查询uni-app官网。主要还是开发小型的软件系统,使用起来非常的方便、快捷、高效。 uniapp中有很多自带的UI,在创建项目的时候,就可以自由选择。而E…

网络编程面试系列-01

1. 应用层中常见的协议都有哪些? 应用层协议(application layer protocol)定义了运行在不同端系统上的应用程序进程如何相互传递报文。 应用层协议 1)DNS:一种用以将域名转换为IP地址的Internet服务,域名系统DNS是因特网使用的命名系统,用来把便于人们使用的机器名字…

Unity类银河恶魔城学习记录1-11 PlayerPrimaryAttack P38

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Player.cs using System.Collections; using System.Collections.Generic…

苹果公司宣布,为Apple Vision Pro打造了超过600款新应用

深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行! 订阅:https://rengongzhineng.io/ 。 2月…

JavaWeb之HTML-CSS --黑马笔记

什么是HTML ? 标记语言:由标签构成的语言。 注意:HTML标签都是预定义好的,HTML代码直接在浏览器中运行,HTML标签由浏览器解析。 什么是CSS ? 开发工具 VS Code --安装文档和安装包都在网盘中 链接:https://p…

FreeRtos的静态方法创建任务和删除示例

需要使用静态方法需要将宏configSUPPORT_STATIC_ALLOCATION1 步骤 1.修改宏configSUPPORT_STATIC_ALLOCATION1运行时候会显示两个函数未定义 vApplicationGetIdleTaskMemory()vApplicationGetTimerTaskMemory() #include &quo…

git整合分支的两种方法——合并(Merge)、变基(Rebase)

问题描述: 初次向git上传本地代码或者更新代码时,总是会遇到以下两个选项。有时候,只是想更新一下代码,没想到,直接更新了最新的代码,但是自己本地的代码并没有和git上的代码融合,反而被覆盖了…

机器学习系列——(六)数据降维

引言 在机器学习领域,数据降维是一种常用的技术,旨在减少数据集的维度,同时保留尽可能多的有用信息。数据降维可以帮助我们解决高维数据带来的问题,提高模型的效率和准确性。本文将详细介绍机器学习中的数据降维方法和技术&#…

浅谈——开源软件的影响力

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 ✨特色专栏&#xff1a…

数据结构与算法:图论(邻接表板子+BFS宽搜、DFS深搜+拓扑排序板子+最小生成树MST的Prim算法、Kruskal算法、Dijkstra算法)

前言 图的难点主要在于图的表达形式非常多,即数据结构实现的形式很多。算法本身不是很难理解。所以建议精通一种数据结构后遇到相关题写个转换数据结构的接口,再套自己的板子。 邻接表板子(图的定义和生成) public class Graph…

Docker 第十一章 : Docker 三剑客之 Swarm (集群管理命令)

第十一章 : Docker 三剑客之 Swarm (集群管理命令) 本章知识点: 本文介绍了Docker三剑客之一的Swarm集群管理工具 , 通过Swarm,用户可以轻松地创建和管理Docker容器集群,实现容器服务的横向扩展和高可用性。Swarm提供了简单易用的命令行界面,使用户能够快速部署和管理…

[EFI]DELL-7472电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况主板 DELL-7472 处理器Intel Core i7-8550U已驱动内存16GB RAM DDR4已驱动硬盘PNY SSD NVME 500GB已驱动显卡Intel UHD Graphics 620已驱动声卡瑞昱 Realtek ALC256 英特尔 High Definition Audio 控制器已驱动网卡瑞昱 RTL8168/8111/8112 Gigabit Ethernet C…

Java I/O 流

内容体系图 文件基础 说明:输入输出是针对内存来说的 常用的文件操作

zabbix监控mariadb数据库

zabbix监控mariadb数据库 1.创建监控用户及授权 [rootchang ~]# mysql -uroot -p123qqq.A MariaDB [(none)]> CREATE USER monitor% IDENTIFIED BY 123qqq.A; MariaDB [(none)]> GRANT REPLICATION CLIENT,PROCESS,SHOW DATABASES,SHOW VIEW ON *.* TO monitor%; Maria…

Coil:Android上基于Kotlin协程的超级图片加载库

Coil:Android上基于Kotlin协程的超级图片加载库 1. coil简介 在当今移动应用程序的世界中,图片加载是一个不可或缺的功能。为了让应用程序能够高效地加载和显示图片,开发人员需要依赖于强大的图片加载库。而今天,我将向大家介绍…

爱上算法:每日算法(24-2月4号)

🌟坚持每日刷算法,😃将其变为习惯🤛让我们一起坚持吧💪 文章目录 [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/)思路CodeJavaC 复杂度 [225. 用队列实现栈](https://leetcode.cn/…

使用java -jar命令运行jar包提示“错误:找不到或无法加载主类“的问题分析

用maven把普通java项目打包成可运行的jar后,打开cmd用java -jar运行此jar包时报错: 用idea运行该项目则没有问题 。 其实原因很简单,我们忽略了2个细节。 java指令默认在寻找class文件的地址是通过CLASSPATH环境变量中指定的目录中寻找的。我…

Seata介绍

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 Seata 中有三⼤模块,分别是 TM、RM 和 TC。其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在⼀起,TC 作为 Seata 的服务端独⽴部署…

SpringMVC-响应数据

一、引子 我们在上一篇文章SpringMVC-组件解析里介绍了SpringMVC框架执行一个请求的过程,并演示了快速使用Controller承接请求。本篇我们将深入介绍SpringMVC执行请求时,如何响应客户端。 二、响应类型 SpringMVC的数据响应方式主要分为两类&#xff…

浅谈QT的几种线程的使用和区别。

简介: 线程是操作系统中的基本执行单元,是一个独立的执行路径。每个线程都有自己的栈空间,用于存储本地变量和函数调用的上下文。多个线程可以在同一进程中并发执行,从而实现并发处理,提高程序的性能和响应能力。 与进…