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

一、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_idfor(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.mzph.cn/news/830102.shtml

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

相关文章

使用 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 密…

《Fundamentals of Power Electronics》——Buck、Boost、Buck-Boost三个电路的CCM-DCM工作特性总结

Buck、Boost、Buck-Boost这三个电路的CCM-DCM工作特性总结如下表所示&#xff1a; Buck、Boost、Buck-Boost这三个电路工作在DCM模式下电压传输比的对比图如下所示&#xff1a; 由上图可知&#xff0c;Buck-Boost电路的工作特性是一条斜率为的直线&#xff0c;Buck电路和Boost电…

RK3588 - RKNN(Rockchip 神经处理单元)的逆向工程

本文翻译自https://jas-hacks.blogspot.com/2024/02/rk3588-reverse-engineering-rknn.html RK3588 NPU 的内部操作和功能主要隐藏在名为RKNPU2的闭源 SDK 中。由于对大型语言模型 (LLM) 的兴趣以及对transform模型最佳矩阵乘法的追求&#xff0c;想了解 RKNPU SDK 新引入的矩阵…

自动开箱机:提升包装物流效率的关键设备

随着电子商务的飞速发展&#xff0c;物流行业面临着重要的挑战和机遇。如何在保证服务质量的同时&#xff0c;提高物流效率&#xff0c;降低成本&#xff0c;成为摆在物流企业面前的重要课题。在这个背景下&#xff0c;自动开箱机以其高效、精准、省力的特点&#xff0c;正逐渐…

OpenMM——教程学习(1)

如何从零开始做一个蛋白小分子动力学模拟 AmberTools将被用来生成输入文件&#xff0c;OpenMM 将被用来运行模拟&#xff0c;模拟平台为在线百度AI Stuio, 并使用GPU加速。 First thing’s first, 到PDB 蛋白数据库下载一需要模拟的靶点晶体&#xff0c;备用。 1. H web server…

一文讲清:什么是供应商管理?供应商管理怎么做?

供应商管理指的是对供应商的了解、选择、开发、使用和控制等综合性管理工作的总称。其目的在于建立起一个稳定可靠的供应商队伍&#xff0c;为企业生产提供可靠的物资供应。但是企业在进行供应商管理往往面临以下问题&#xff1a; 1、招投标&#xff0c;信息不透明 这主要表…

R语言的基本图形

一&#xff0c;条形图 安装包 install.packages("vcd") 绘制简单的条形图 barplot(c(1,2,4,5,6,3)) 水平条形图 barplot(c(1,2,4,5,6,3),horiz TRUE) 堆砌条形图 > d1<-c("Placebo","Treated") > d2<-c("None",&qu…

你不需要总是在 React 中使用 useState

在我审查的一个拉取请求中&#xff0c;我注意到在许多拉取请求中看到的一种模式。React 组件具有多个 UI 状态&#xff0c;例如 loading、error 和 success。 作者使用了多个 useState 钩子来管理这些状态&#xff0c;这导致代码难以阅读且容易出错&#xff0c;例如&#xff1a…

hadoop命令

hadoop命令 目录 hadoop命令 1.查看文件下面有哪些文件和目录 2.获取文件信息 查看文件内容 3.创建一个文件夹 4.剪切 1&#xff09;从本地hadoop剪切到hdfs并上传到hdfs 2&#xff09;剪切 从hdfs剪切到本地hadoop目录上 5.删除 1&#xff09;递归删除 2&#xff0…

springboot权限验证学习-下

上篇讲了rbac对于菜单的权限&#xff0c;下面准备完成按钮权限以及行数据和列数据权限 权限控制(按钮权限) 权限控制 操作权限就是将操作视为资源&#xff0c;比如删除操作&#xff0c;有些人可以有些人不行。于后端来说&#xff0c;操作就是一个接口。于前端来说&#xff0…

秋招后端开发面试题 - JVM底层原理

目录 JVM底层原理前言面试题Java 对象的创建过程&#xff1f;什么是指针碰撞&#xff1f;什么是空闲列表&#xff1f;/ 内存分配的两种方式&#xff1f;JVM 里 new 对象时&#xff0c;堆会发生抢占吗&#xff1f;JVM 是怎么设计来保证线程安全的&#xff1f;/ 内存分配并发问题…

k8s pod使用sriov

之前的文章中讲了k8s multus的使用&#xff0c;本章节来讲述下如何使用multus来实现sriov的使用。 一、sriov 简介 SR-IOV在2010年左右由Intel提出&#xff0c;但是随着容器技术的推广&#xff0c;intel官方也给出了SR-IOV技术在容器中使用的开源组件&#xff0c;例如&#…

3MF体积设计扩展

3MF 联盟最近宣布了他们最新的体积设计扩展&#xff08;volumetric design extension&#xff09;&#xff0c;用于通过基于体积的描述来编码几何形状和空间多样性属性。 该组织致力于推进 3D 打印的通用规范&#xff0c;目前正在新扩展达到 1.0 之前征求公众反馈。 NSDT工具推…

OpenCV 实现重新映射

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV 实现霍夫圆变换 下一篇 :OpenCV实现仿射变换 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 一个。使用 OpenCV 函数 cv&#xff1a;&#xff1a;remap 实现简单的重新…

20240428如何利用IDM下载磁链视频

缘起&#xff1a; https://weibo.com/tv/show/1034:4864336909500449 中国获奖独立纪录片《阿辉》揭秘红灯区“教父”的生存法则 5,751次观看 1年前 发布于 陕西 身为里中横 67.7万粉丝 互联网科技博主 微博原创视频博主 头条文章作者 https://weibo.com/tv/show/1034:4864…

数据通信-A

数据通信 一、数据通信网络基础二、VRP系统三、eNSP配置命令 不是从零开始&#xff0c;有一些基础&#xff0c;主要记录配置命令。一、数据通信网络基础 图标&#xff1a;主要是认识第一行。 常见术语&#xff1a;数据通信网络最基本的功能是实现数据互通。 数据载荷&#…

解决IDEA下springboot项目打包没有主清单属性

1.问题出现在SpringBoot学习中 , 运行maven打包后无法运行 报错为spring_boot01_Demo-0.0.1-SNAPSHOT.jar中没有主清单属性 SpringBoot版本为 2.6.13 Java 版本用的8 解决方法 1.执行clean 删除之前的打包 2.进行打包规范设置 2.1 3.进行问题解决 (借鉴了阿里开发社区) 使用…

[嵌入式系统-53]:嵌入式系统集成开发环境大全

目录 一、嵌入式系统集成开发环境分类 二、由MCU芯片厂家提供的集成开发工具 三、由嵌入式操作提供的集成开发工具 四、由第三方工具厂家提供的集成开发工具 一、嵌入式系统集成开发环境分类 嵌入式系统集成开发工具和集成开发环境可以按照不同的分类方式进行划分&#xff…

【LAMMPS学习】八、基础知识(5.2)粒度模型

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

将针孔模型相机 应用到3DGS

Motivation 3DGS 的 投影采用的是 CG系的投影矩阵 P P P, 默认相机的 principal point (相机光心) 位于图像的中点处。但是 实际应用的 绝大多数的 相机 并不满足这样一个设定&#xff0c; 因此我们 需要根据 f , c x , c y {f,c_x, c_y} f,cx​,cy​ 这几个参数重新构建3D …