当前位置: 首页 > news >正文

MySQL:如果用left join的话,左边的表一定是驱动表吗

一、前言

  在日常开发过程中关于MySQL的优化方面,我们知道小表驱动大表原理。例如left join,放在左边的表作为驱动表。但是用left join的话,左边的表一定是驱动表吗,本文将通过案例分析给出详细分析。

二、概念

  在MySQL中,JOIN操作涉及到两个或多个表的连接,其中一个表被称为驱动表(也称为外表),另一个表或多个表被称为被驱动表(也称为内表或从表)。

  驱动表(外表):在JOIN操作中,首先被访问的表称为驱动表。

  被驱动表(内表或从表):在JOIN操作中,与驱动表进行匹配的表称为被驱动表。

三、优化策略(小表驱动大表原理)

  在MySQL的JOIN操作中,当涉及到两个或多个表的连接时,其中一个表被选为驱动表(小表),另一个表作为被驱动表(大表)。小表驱动大表的原理就是尽量让数据量较小的表作为驱动表,通过其数据去匹配大数据量的表,以减少循环匹配的次数,从而提高查询性能。

示例:
  假设我们有两个表A和B,其中A表有1000行数据,B表有100万行数据。如果以A表作为驱动表去连接B表,那么最多只需要循环1000次;而如果以B表作为驱动表去连接A表,则需要循环100万次。显然,选择A表作为驱动表将大大提高查询性能。

选择小表作为驱动表的好处:

  减少循环次数:当驱动表的数据量较小时,循环的次数会相应减少,从而减少了整体的计算量。反之,如果大表作为驱动表,则需要多次循环遍历大表的数据去匹配小表,这将大大增加计算量。

  利用索引:如果小表上有合适的索引,MySQL可以更快地定位到需要的数据行,进一步减少扫描的行数。同时,索引的使用也可以提高JOIN操作的效率。

  优化器决策:MySQL的优化器会根据表的统计信息、索引情况、查询条件等因素来自动选择最佳的驱动表。优化器的目标是找到一种执行计划,使得查询的代价(如I/O操作、CPU时间等)最小。

四、案例分析

  我们在编写SQL的时候,通常情况下是这样子的
  LEFT JOIN:在左连接中,左边的表通常作为驱动表。
  RIGHT JOIN:在右连接中,右边的表作为驱动表。
  INNER JOIN:对于内连接,MySQL会自动选择数据量较小的表作为驱动表。

这是通常情况下,下面我们准备一些测试数据:

1. 准备数据:

a1表
在这里插入图片描述
a2表
在这里插入图片描述

2.准备查询语句1和查询语句2

语句1
select * from a1 left join a2 on(a1.f1=a2.f1) and (a1.f2=a2.f2); 语句2
select* from a1 left join a2 on(a1.f1=a2.f1)where (a1.f2=a2.f2);

3. 查询语句1的执行结果
在这里插入图片描述

4. 查询语句2的执行结果
在这里插入图片描述

5. 语句1的EXPLAIN执行结果分析
在这里插入图片描述
从EXPLAIN执行计划中看的出来

  驱动表是表a1,被驱动表是表a2。

  由于表a2的f1字段上没有索引,所以使用的是 Block Nested Loop Join(简称 BNL) 算法。

BNL算法基本原理

  将外层循环的结果集存入join buffer:在BNL算法中,外层循环(通常是较小的表或结果集)的行或结果集会被存储在一个称为join buffer的内存区域中。

  内层循环与buffer中的记录做比较:内层循环(通常是较大的表或结果集)的每一行数据会与整个buffer中的记录进行比较,而不是像传统的Nested Loop Join(NLJ)算法那样,每次只与外层循环的一行进行比较。

结合算法与执行计划语句1的执行过程如下:

  ①. 把表a1的内容读入join_buffer 中

  ②. 顺序扫描表a2,对于每一行数据,判断条件(a1.f1=a2.f1) and (a1.f2=a2.f2)是否满足,满足条件的记录, 作为结果集的一行返回。如果语句中有 where 子句,需要先判断 where 部分满足条件后,再返回。

  ③. 表a2扫描完成后,对于没有被匹配的表a1的行,把剩余字段补上 NULL,再放入结果集中。

6. 语句2的EXPLAIN执行结果分析
在这里插入图片描述
从EXPLAIN执行计划中看的出来

  以表a2为驱动表的。

语句2的执行过程
  顺序扫描表a2,每一行用a2.f1到表a1中去查,匹配到记录后判断a1.f2=a2.f2 是否满足,满足条件的话就作为结果集的一部分返回。

为什么呢,我们执行一下show warnings;看看优化器是怎么做的。
语句1
在这里插入图片描述

语句2
在这里插入图片描述

  在 MySQL 里,NULL 跟任何值执行等值判断和不等值判断的结果,都是 NULL。这里包括, select NULL = NULL 的结果,也是返回 NULL。

  因此,语句2里面 where a1.f2=a2.f2 就表示,查询结果里面不会包含 a2.f2是NULL的行,这样这个left join的语义就是“找到这两个表里面,f1、f2 对应相同的行。

  对于表a1中存在,而表a2中匹配不到的行,就放弃。这样,这条语句虽然用的是 left join,但是语义跟 join 是一致的。

  因此,优化器就把这条语句的 left join 改写成了 join,然后因为表 a1 的 f1 上有索引,就把表 a2 作为驱动表。

五、结论

1、即使我们在SQL语句中写成left join,执行过程还是有可能不是从左到右连接的。也就是说,使用left join时,左边的表不一定是驱动表。

2、如果需要left join的语义,就不能把被驱动表的字段放在where条件里面做等值判断或不等值判断,必须都写在on里面。

六、总结

通过对案例的分析,我们在写sql的时候,就有了优化方案:

1. 用小结果集驱动大结果集,减少外层循环的数据量

2. 如果小结果集和大结果集连接的列都是索引列,mysql在join时也会选择用小结果集驱动大结果集,因为索引查询的成本是比较固定的,这时候外层的循环越少,join的速度便越快。

3. 为匹配的条件增加索引:争取使用Index Nested-Loop Join,减少内层表的循环次数

4. 增大join buffer size的大小:当使用Block Nested-Loop Join时,一次缓存的数据越多,那么外层表循环的次数就越少,减少不必要的字段查询。

5. 当用到Block Nested-Loop Join时,字段越少,join buffer 所缓存的数据就越多,外层表的循环次数就越少。

相关文章:

  • Diffusion Policy:基于扩散模型的机器人动作生成策略
  • CLIP源码详解:clip.py 文件
  • 【除了知乎,大家都在逛什么?持续更新~~】
  • python数据分析——apply 1
  • 全局查询筛选器适用场景 以及各场景示例
  • 算法刷题day54:搜索(一)
  • Alamofire常见GET/POST等请求方式的使用,响应直接为json
  • HQL面试题练习 —— 取出累计值与1000差值最小的记录
  • 链表经典题目—相交链表和链表倒数第k个节点
  • 基于香橙派 Ai Pro的ROS Qt人机交互软件部署指南
  • 漫步者x1穷鬼耳机双耳断连
  • idea配置ssh、sftp连接服务器,docker插件使用,极其方便,无需再开第三方软件去操作服务器了,集成用于Idea一体
  • 【Java继承】(超级详细!!!)
  • 【pm2 - sdk 集成到程序中,典型用法】
  • 堆结构知识点复习——玩转堆结构
  • 2017前端实习生面试总结
  • exif信息对照
  • java中的hashCode
  • KMP算法及优化
  • mysql innodb 索引使用指南
  • MySQL几个简单SQL的优化
  • MySQL数据库运维之数据恢复
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 复杂数据处理
  • 规范化安全开发 KOA 手脚架
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 前端面试之闭包
  • 容器服务kubernetes弹性伸缩高级用法
  • 深入浅出webpack学习(1)--核心概念
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 思考 CSS 架构
  • 微信开源mars源码分析1—上层samples分析
  • 物联网链路协议
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • #QT(一种朴素的计算器实现方法)
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (1)STL算法之遍历容器
  • (13)Hive调优——动态分区导致的小文件问题
  • (C#)一个最简单的链表类
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (六)c52学习之旅-独立按键
  • (算法)Travel Information Center
  • (一)python发送HTTP 请求的两种方式(get和post )
  • ***详解账号泄露:全球约1亿用户已泄露
  • .java 9 找不到符号_java找不到符号
  • .libPaths()设置包加载目录
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET Framework杂记
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .NET企业级应用架构设计系列之技术选型
  • .Net小白的大学四年,内含面经
  • @Autowired和@Resource装配
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798