架构师系列-MYSQL调优(五)- JOIN、in及exists优化

JOIN算法原理

JOIN 是 MySQL 用来进行联表操作的,用来匹配两个表的数据,筛选并合并出符合我们要求的结果集。JOIN 操作有多种方式,取决于最终数据的合并效果。常用连接方式的有以下几种:

 驱动表的定义

什么是驱动表 ?

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

驱动表的选择要遵循一个规则:

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

 三种JOIN算法

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

  • 简单来说嵌套循环连接算法就是一个双层for 循环 ,通过循环外层表的行数据,逐个与内层表的所有行数据进行比较来获取结果.

  • 这种算法是最简单的方案,性能也一般。对内循环没优化。

  • 例如有这样一条SQL:

-- 连接用户表与订单表 连接条件是 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;}}
}

匹配过程如下图

  • SNL 的特点

    • 简单粗暴容易理解,就是通过双层循环比较数据来获得结果

    • 查询效率会非常慢,假设 A 表有 N 行,B 表有 M 行。SNL 的开销如下:

      • A 表扫描 1 次。
      • B 表扫描 M 次。
      • 一共有 N 个内循环,每个内循环要 M 次,一共有内循环 N * M 次

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

  • Index Nested-Loop Join 其优化的思路: 主要是为了减少内层表数据的匹配次数 , 最大的区别在于,用来进行 join 的字段已经在被驱动表中建立了索引。

  • 从原来的 匹配次数 = 外层表行数 * 内层表行数 , 变成了 匹配次数 = 外层表的行数 * 内层表索引的高度 ,极大的提升了 join的性能。

  • order 表的 user_id 为索引的时候执行过程会如下图:

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

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

  • 如果 join 的字段有索引,MySQL 会使用 INL 算法。如果没有的话,MySQL 会如何处理?

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

  • 在外层循环扫描 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. 永远用小结果集驱动大结果集(其本质就是减少外层循环的数据数量)

  2. 为匹配的条件增加索引(减少内层表的循环匹配次数)

  3. 增大join buffer size的大小(一次缓存的数据越多,那么内层包的扫表次数就越少)

  4. 减少不必要的字段查询(字段越少,join buffer 所缓存的数据就越多

in和exists函数 

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

创建部门表与员工表,并插入数据

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);

1) in 函数

  • 假设: department表的数据小于 employee表数据, 将所有部门下的员工都查出来,应该使用 in 函数
SELECT * FROM employee e WHERE e.dep_id IN (SELECT id FROM department);

in函数的执行原理

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

-- 先循环: 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) exists 函数 

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

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

exists 特点

exists 子句返回的是一个 布尔值,如果有返回数据,则返回值是true,反之是false

如果结果为 true , 外层的查询语句会进行匹配,否则 外层查询语句将不进行查询或者查不出任何记录。

 exists 函数的执行原理

-- 先循环: 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];}
}

3) in 和 exists 的区别

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

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

  • 一句话: in后面跟的是小表,exists后面跟的是大表。

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

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

相关文章

Bert语言大模型基础

一、Bert整体模型架构 基础架构是transformer的encoder部分&#xff0c;bert使用多个encoder堆叠在一起。 主要分为三个部分&#xff1a;1、输入部分 2、注意力机制 3、前馈神经网络 bertbase使用12层encoder堆叠在一起&#xff0c;6个encoder堆叠在一起组成编码端&#xf…

Spring Boot中判断轨迹数据是否经过设置的打卡点,且在PGSQL中把点拼接成线,判断某个点是否在线上或在线的50米范围内

问题描述 轨迹数据判断是否经过打卡点&#xff0c;轨迹数据太多&#xff0c;循环判断的话非常消耗内存。解决办法只需要把所有轨迹数据点拼成了一条线&#xff0c;然后只需要循环打卡点即可&#xff0c;打卡点不多&#xff0c;一般不会超过100个&#xff0c;如果多的话&#x…

R可视化:桑基图展示数据层流动

介绍 以桑基图形式展示数据分布情况 加载R包 knitr::opts_chunk$set(message = FALSE, warning = FALSE) library(tidyverse) library(ggalluvial)# rm(list = ls()) options(stringsAsFactors = F) options(future.globals.maxSize = 10000 * 1024^2) 导入数据 metadata…

【计算机毕业设计】大学校园图书角管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

【Flutter】One or more plugins require a higher Android SDK version.

问题描述 项目里多个组件需要更高版本的Android SDK One or more plugins require a higher Android SDK version.解决方案&#xff1a; 报错提示requires Android SDK version 34 按提示修改android项目app里build.gradle的compileSdkVersion 为34 android {compileSdkVe…

node.js-包

包的概念 包&#xff1a;将模块&#xff0c;代码&#xff0c;其他资料聚合成的一个文件夹 包分类&#xff1a; 1.项目包&#xff1a;主要用于编写项目和业务逻辑的文件夹 2.软件包&#xff1a;封装工具和方法供开发者使用&#xff08;一般使用npm管理&#xff09; 1&#…

mysql的DDL语言和DML语言

DDL语言&#xff1a; 操作数据库&#xff0c;表等&#xff08;创建&#xff0c;删除&#xff0c;修改&#xff09;&#xff1b; 操作数据库 1&#xff1a;查询 show databases 2:创建 创建数据库 create database 数据库名称 创建数据库&#xff0c;如果不存在就创建 crea…

MySQL—一条查询SQL语句的完整执行流程

MySQL—一条查询SQL语句的完整执行流程 表结构和数据如下&#xff1a; 我们分析的sql语句如下&#xff1a; select tb_id,tb_name,tb_address from tb_user where tb_id 66;大体来说&#xff0c;MySQL可以分为Server层和存储引擎层两部分: Server层 包括:连接器、查询缓存、…

使用Java实现动态心形图案

一、引言 在计算机图形学中&#xff0c;动态图案的生成和显示一直是一个令人兴奋的话题。心形图案作为情感表达的一种常见方式&#xff0c;在编程领域也颇受欢迎。本文将介绍如何使用Java编程语言实现动态心形图案&#xff0c;并附上相应的代码片段。 二、心形曲线的数学表达…

如何使用 ArcGIS Pro 快速为黑白地图配色

对于某些拍摄时间比较久远的地图&#xff0c;限于当时的技术水平只有黑白的地图&#xff0c;针对这种情况&#xff0c;我们可以通过现在的地图为该地图进行配色&#xff0c;这里为大家讲解一下操作方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微…

使用大卫的k8s监控面板(k8s+prometheus+grafana)

问题 书接上回&#xff0c;对EKS&#xff08;AWS云k8s&#xff09;启用AMP&#xff08;AWS云Prometheus&#xff09;监控AMG(AWS云 grafana)&#xff0c;上次我们只是配通了EKSAMPAMG的监控路径。这次使用一位大卫老师的grafana的面板&#xff0c;具体地址如下&#xff1a; ht…

汽车IVI中控开发入门及进阶(十五):AUTOSAR

前言: 随着汽车四化的进行,汽车电子系统standard标准化和coperation互操作性变得重要, AUTOSAR(AUTomotive Open System Architecture 汽车开放系统架构)框架已成为汽车行业的基础支柱。 AUTOSAR始自2000年,当时认识到标准化是有必要

Redis入门到通关之Redis数据结构-Set篇

文章目录 ☃️概述☃️数据结构☃️源码☃️其他 &#x1f308; 欢迎莅临我的个人主页&#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a; 我是请回答1024&#xff0c;一名Java领域深耕多年…

解读币安Megadrop:如何参加第一期BounceBit活动?

币安推出新的代币发行平台 Megadrop&#xff0c;第一期为 BounceBit。 跟 launchpool 相比&#xff0c; 主要不同是 1&#xff09;锁仓 bnb 有收益的倍数加成 2&#xff09;做任务有收益加成。 我认为核心目的有两个&#xff1a; 1&#xff09;更多收益给 BNB 长期持有者&am…

jenkins修改全局安全配置之后登录错误

教训&#xff08;流泪&#xff09; 事情是这样的&#xff0c;第一次我需要用单点登录集成jenkins&#xff0c;jenkins可以通过插件的方式支持cas协议&#xff0c;我当时也不很懂&#xff0c;经过我学网上的一顿乱配置&#xff0c;jenkis上不去了&#xff0c;虽然这是公司本地环…

大数据——Zookeeper ZBA协议(四)

Zookeeper ZAB协议 概述 ZAB(Zookeeper Automic Broadcast)是一套专门为Zookeeper设计的用于进行原子广播和崩溃恢复的协议ZAB协议主要包含了两个功能 原子广播&#xff1a;保证数据一致性崩溃恢复&#xff1a;保证集群的高可用 ZAB协议本身是基于2PC算法来进行的设计&#…

记一次 Vscode + Latex 正向/反向搜索忽然失效

遥望大半个月前&#xff0c;完成论文撰写后&#xff0c;这些天虽然多次打开项目&#xff0c;但我真的一个字都没动过&#xff0c;今天想着开始着手修改一下&#xff0c;打开项目发现正向/反向搜索忽然失效了&#xff0c;感觉浑身有蚂蚁在爬&#xff0c;思索再三后找到问题&…

【数学归纳法 反证法】菲蜀定理

裴蜀定理&#xff08;或贝祖定理&#xff0c;Bzout’s identity&#xff09;得名于法国数学家艾蒂安裴蜀&#xff0c;说明了对任何整数a、b和它们的最大公约 数d&#xff0c;关于未知数x和y的线性不定方程&#xff08;称为裴蜀等式&#xff09;&#xff1a;若a,b是整数,且&…

[测试]ChaosBlade: 丢包、延迟、断网、磁盘、cpu占用、内存占用等资源耗尽故障注入利器--编辑中

目录 ChaosBlade是什么? ChaosBlade可以制造哪些工况/故障? 使用文档 git仓库:chaosblade/README_CN.md at master chaosblade-io/chaosblade GitHub ChaosBlade是什么? ChaosBlade: 一个简单易用且功能强大的混沌实验实施工具 ChaosBlade是阿里巴巴开源的一款遵循混…

[图解]软件开发中的糊涂用语-04-为什么要追究糊涂用语

0 00:00:00,030 --> 00:00:05,620 今天呢&#xff0c;我们来说一个为什么要追究糊涂用语的问题 1 00:00:06,310 --> 00:00:06,548 2 00:00:06,548 --> 00:00:11,077 大家知道我们前些天都发了好几个视频 3 00:00:11,077 --> 00:00:13,461 追究这个糊涂用语 4 00…