【MySQL 数据宝典】【索引原理】- 004 优化示例-join in exist

news2024/10/7 10:24:40

一、join 优化原理

1.1 基本连接方式介绍

image.png
JOIN 是 MySQL 用来进行联表操作的,用来匹配两个表的数据,筛选并合并出符合我们要求的结果集。

1.2 驱动表的定义

1.2.1 什么是驱动表

  • 多表关联查询时,第一个被处理的表就是驱动表,使用驱动表去关联其他表.
  • 驱动表的确定非常的关键,会直接影响多表关联的顺序,也决定后续关联查询的性能

1.2.2 选择驱动表的基本原则

在对最终的结果集没有影响的前提下,优先选择结果集最小的那张表作为驱动表

1.3 常见的 Join 算法

1.3.1 Simple Nested-Loop Join( 简单的嵌套循环连接 )

简单来说嵌套循环连接算法就是一个双层for 循环 ,通过循环外层表的行数据,逐个与内层表的所有行数据进行比较来获取结果
这种算法是最简单的方案,性能也一般。对内循环没优化。

例子
-- 连接用户表与订单表 连接条件是 u.id = o.user_id
select * from user t1 left join order t2 on t1.id = t2.user_id;
-- user表为驱动表,order表为被驱动表

转化成代码的思路是:

for(user表行 uRow : user表){
    for(Order表的行 oRow : order表){
        if(uRow.id = oRow.user_id){
            return uRow;
        }
    }
}

匹配流程如下所示:
image.png

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

  • Index Nested-Loop Join 其优化的思路:  主要是为了减少内层表数据的匹配次数 , 最大的区别在于,用来进行 join 的字段已经在被驱动表中建立了索引。
  • 从原来的  匹配次数 = 外层表行数 * 内层表行数 , 变成了  匹配次数 = 外层表的行数 * 内层表索引的高度  ,极大的提升了 join的性能。
  • 当  order  表的   user_id  为索引的时候执行过程会如下图:

image.png
注意:使用Index Nested-Loop Join 算法的前提是匹配的字段必须建立了索引。

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

  • 如果 join 的字段有索引,MySQL 会使用 INL 算法。如果没有的话,MySQL 会如何处理?
  • 因为不存在索引了,所以被驱动表需要进行扫描。这里 MySQL 并不会简单粗暴的应用 SNL 算法,而是加入了 buffer 缓冲区,降低了内循环的个数,也就是被驱动表的扫描次数。

image.png

  • 在外层循环扫描 user表中的所有记录。扫描的时候,会把需要进行 join 用到的列都缓存到 buffer 中。buffer 中的数据有一个特点,里面的记录不需要一条一条地取出来和 order 表进行比较,而是整个 buffer 和 order表进行批量比较。
  • 如果我们把 buffer 的空间开得很大,可以容纳下 user 表的所有记录,那么 order 表也只需要访问一次。
  • MySQL 默认 buffer 大小 256K,如果有 n 个 join 操作,会生成 n-1 个 join buffer。
mysql> show variables like '%join_buffer%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| join_buffer_size | 262144 |
+------------------+--------+

mysql> set session join_buffer_size=262144;
Query OK, 0 rows affected (0.00 sec)

1.4 总结

  1. 永远用小结果集驱动大结果集(其本质就是减少外层循环的数据数量)
  2. 为匹配的条件增加索引(减少内层表的循环匹配次数)
  3. 增大join buffer size的大小(一次缓存的数据越多,那么内层包的扫表次数就越少)
  4. 减少不必要的字段查询(字段越少,join buffer 所缓存的数据就越多

二、in 和 exist 函数

上面我们说了 小表驱动大表,就是小的数据集驱动大的数据集, 主要是为了减少数据库的连接次数,根据具体情况的不同,又出现了两个函数 existsin 函数

2.1 数据准备

-- 部门表
CREATE TABLE department (
  id INT(11) PRIMARY KEY,
  deptName VARCHAR(30) ,
  address VARCHAR(40) 
) ;

-- 部门表测试数据
INSERT INTO `department` VALUES (1, '研发部', '1层');
INSERT INTO `department` VALUES (2, '人事部', '3层');
INSERT INTO `department` VALUES (3, '市场部', '4层');
INSERT INTO `department` VALUES (5, '财务部', '2层');

-- 员工表
CREATE TABLE employee (
  id INT(11) PRIMARY KEY,
  NAME VARCHAR(20) ,
  dep_id INT(11) ,
  age INT(11) ,
  salary DECIMAL(10, 2)
);

-- 员工表测试数据
INSERT INTO `employee` VALUES (1, '鲁班', 1, 15, 1000.00);
INSERT INTO `employee` VALUES (2, '后裔', 1, 22, 2000.00)
INSERT INTO `employee` VALUES (4, '阿凯', 2, 20, 3000.00);
INSERT INTO `employee` VALUES (5, '露娜', 2, 30, 3500.00);
INSERT INTO `employee` VALUES (6, '李白', 3, 25, 5000.00);
INSERT INTO `employee` VALUES (7, '韩信', 3, 50, 5000.00);
INSERT INTO `employee` VALUES (8, '蔡文姬', 3, 35, 4000.00);
INSERT INTO `employee` VALUES (3, '孙尚香', 4, 20, 2500.00);

2.2 in 函数

假设: department表的数据小于 employee表数据, 将所有部门下的员工都查出来,应该使用 in 函数

-- 编写SQL,使in 函数
SELECT * FROM employee e WHERE e.dep_id IN (SELECT id FROM department);

执行原理

  1. in 语句, 只执行一次, 将 department  表中的所有id字段查询出来并且缓存.
  2. 检查 department  表中的id与 employee 表中的    dep_id 是否相等, 如果相等 添加到结果集, 直到遍历完department  所有的记录.

image.png

-- 先循环: select id from department; 相当于得到了小表的数据
for(i = 0; i < $dept.length; i++){  -- 小表
	-- 后循环: select * from employee where e.dep_id  = d.id;
	for(j = 0 ; j < $emp.legth; j++){  -- 大表
	
		if($dept[i].id == $emp[j].dep_id){
			$result[i] = $emp[j]
			break;
		}
		
	}
}

结论

如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用 in

2.3 exist 函数

假设: department表的数据大于 employee表数据, 将所有部门下的的员工都查出来,应该使用 exists 函数.

 SELECT * FROM employee e WHERE EXISTS 
(SELECT id FROM department d WHERE d.id = e.dep_id);

特点

exists 子句返回的是一个 布尔值,如果有返回数据,则返回值是true,反之是false
如果结果为 true , 外层的查询语句会进行匹配,否则 外层查询语句将不进行查询或者查不出任何记录
image.png

执行原理分析

-- 先循环: SELECT * FROM employee e;
-- 再判断: SELECT id FROM department d WHERE d.id = e.dep_id

for(j = 0; j < $emp.length; j++){  -- 小表

-- 遍历循环外表,检查外表中的记录有没有和内表的的数据一致的, 匹配得上就放入结果集。
	if(exists(emp[i].dep_id)){   -- 大表
		$result[i] = $emp[i];
	}
}

2.4 in vs exist

  • 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用 in
  • 如果主查询得出的结果集记录较少,子查询中的表较大且又有索引时应该用  exists
  • 一句话:  in后面跟的是小表,exists后面跟的是大表。

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

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

相关文章

笔记:能量谱密度与功率谱密度(二)

目录 一、ESD与PSD的定义、单位、性质 二、对ESD与PSD的直观理解 三、总结&#xff1a; 某物理量的“分布”在离散系统中&#xff0c;各点(纵坐标含义&#xff09;的物理意义仍然是该物理量&#xff0c;而在连续系统中&#xff0c;各点&#xff08;纵坐标含义&#xff09;的物…

注意力机制略解

引子 例如&#xff0c;现在需要拟合函数f(x)&#xff0c;我们已知函数上的若干点&#xff08;xi&#xff0c;yi&#xff09; 现在我们想知道在自变量取x’的时候&#xff0c;函数值y’为多少 正常的思路比如拉格朗日插值&#xff0c;牛顿插值&#xff0c;直接去估计函数的表…

Linux网络服务-DHCP

一、DHCP工作原理 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;&#xff1a;用于自动获取IP地址 1.客户端会发送一个广播DHCP Discover报文去寻找DHCP服务器 2.客户端只会接收第一个回复的DHCP服务器的报文 3.服务器会发…

评估LLM

文章目录 一、LLM 基准测试LLM 排行榜 二、评估指标1、传统指标2、非传统指标2.1 基于嵌入的方法2.2 其他基于语言模型的指标2.3 LLM 辅助方法GPTScoreG-Eval 3、可能的陷阱 三、评估基于LLM的应用1、选择评估指标2、评估 评估方法3、构建您的评估集 四、工具1、OpenAI 评估2、…

海外三大AI图片生成器对比(Stable Diffusion、Midjourney、DALL·E 3)

Stable Diffusion DreamStudio 是Stable Diffusion 的官方网页&#xff0c;价格便宜&#xff0c;对图片的操作性强&#xff0c;但同时编辑页面不太直观&#xff0c;对使用者的要求较高。 与 DALLE 和 Midjourney 不同&#xff0c;Stable Diffusion 是开源的。这也意味着&…

微服务:Nacos注册中心

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Nacos注册中心 一、服务注册与发现1.启动Nacos…

【算法每日一练】

蛮有意思的的一道题&#xff0c;最后要判断能否成为一种1~n的全排列&#xff0c;我最这样做的&#xff1a; 整个数组先排序一下。假设遍历到了i&#xff0c;那就判断前面b和r的个数&#xff0c;但是有想到了后面可能还会对前面的结果产生影响&#xff0c;所以就抛弃了这个想法…

项目|保障房房产管理系统,政务房产解决方案

一、系统概况 保障房管理系统是是为了落实中央关于住房保障的相关政策&#xff0c;实现对低收入家庭住房状况的调查管理、保障计划及落实管理、保障申请及审核管理、保障户和保障房源档案管理等。 针对政府保障房产管理的一站式解决方案&#xff0c;专注于为解决复杂、繁琐的…

java-stream流案例

需求 代码 Vote类 // 1. 定义一个投票类 public class Vote {private String name;private ArrayList<String> voteList;public Vote(String name, ArrayList<String> voteList) {this.name name;this.voteList voteList;}public String getName() {return nam…

《Fundamentals of Power Electronics》——三端电池的旋转、负载差分连接

以下是关于三端电池的旋转的相关知识点&#xff1a; Buck电路、Boost电路和Buck-Boost电路均包含一个与单刀单掷开关相连的电感。如下图所示。 将上图中的电感和开关网络视为一个标有a,b,c三端的基础电池。该电池在电源和负载之间有三种不同的连接方式。a-A b-B c-C连接方式组…

数字信号的产生与检测——DSP学习笔记六

本专栏的博客的图片大部分来源于老师的PPT&#xff0c;本博客只是博主对于上课内容的知识结构的分析和梳理。 几种数字信号的产生 正弦波信号 多项式逼近(除了泰勒展开&#xff0c;还有一种方法是切比雪夫逼近法&#xff0c;感兴趣可以自己去了解一下&#xff09; 查找表 核心思…

可编程SG-8018系列晶体振荡器

近年来&#xff0c;由于越来越需要更小的电子设备&#xff0c;使其在更广泛的环境中具有更大的功率和功能包括极端0.工厂和工厂设备。爱普生晶振针对市场将开发了可编程晶体振荡器系列产品新的SG-8018系列产品,共四种型号分别为SG-8018CA、SG-8018CB、SG-8018CE、SG8018CG&…

Asp .Net Core 系列:国际化多语言配置

文章目录 概述术语 本地化器IStringLocalizer在服务类中使用本地化 IStringLocalizerFactoryIHtmlLocalizerIViewLocalizer 资源文件区域性回退 配置 CultureProvider内置的 RequestCultureProvider实现自定义 RequestCultureProvider使用 Json 资源文件 设计原理IStringLocali…

Java小白福音丨保姆级的JDK+Eclipse+其他常用软件安装教程!

是的我看见到处是阳光 JDK正在安装 新世界来得像梦一样 让我暖洋洋 你的Java学习还在继续吗 你的JDK安装了吗 这儿有一份开发软件安装新教程 你不想学学吗 明天一早&#xff0c; 我猜阳光会好 我要把自己打扫 把破旧的套路丢掉 哦这样多好 加油吧Java少年 前言 想学习Java&…

使用 SSH 密钥配置 Git 账号需要以下步骤

1、生成 SSH 密钥&#xff1a; 如果你还没有 SSH 密钥&#xff0c;可以使用以下命令在电脑终端中生成一个新的 SSH 密钥&#xff1a; ssh-keygen -t rsa -b 4096 -f /Users/XXXX/.ssh/id_rsa_my_personal -C "your_emailexample.com" ssh-keygen 是用于生成 SSH 密…

面试:Redis

目录 一、缓存穿透 1、解决方案一&#xff1a; 2、解决方案二&#xff1a; 二、缓存击穿 1、解决方案一&#xff1a; 2、解决方案二&#xff1a; 三、缓存雪崩 1、解决方案一&#xff1a; 2、解决方案二&#xff1a; 3、解决方案三&#xff1a; 4、解决方案四&#x…

Java对象在堆和栈上的存储(对象布局,待完善)

0、前言 这里提到的 Java 对象不仅仅包含引用类型&#xff08;Object&#xff09;&#xff0c;还包含基本数据类型&#xff08;boolean、int、long、float、double&#xff09;。文中部分图片来源于 B站 黑马程序员。 1、在栈上的数据存储 1.1、局部变量 局部变量包含以下情…

过滤器Filter --学习笔记

什么是Filter&#xff1f; Filter表示过滤器&#xff0c;是 JavaWeb三大组件(Servlet、Filter、Listener)之一过滤器可以把对资源的请求拦截下来&#xff0c;从而实现一些特殊的功能过滤器一般完成一些通用的操作&#xff0c;比如&#xff1a;登录校验、统一编码处理、敏感字符…

NLP发展及其详解

一、RNN(循环神经网络) 在这里附上一个很好的笔记 零基础入门深度学习(5) - 循环神经网络 RNN(循环神经网络)的结构特点在于其循环单元的设计,这种设计允许网络在处理序列数据时保持对之前信息的记忆。下面详细解释RNN的结构: 循环单元:RNN的循环单元是网络的核心,它…

《QT实用小工具·四十五》可以在界面上游泳的小鱼

1、概述 源码放在文章末尾 该项目实现了灵动的小鱼&#xff0c;可以在界面上跟随鼠标点击自由的游泳&#xff0c;项目demo演示如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #include "magicfish.h" #include <QtMath> #include <QPainter>…