MSQL系列(十) Mysql实战-Join驱动表和被驱动表如何区分

Mysql实战-Join驱动表和被驱动表如何区分

前面我们讲解了Mysql的查询连接Join的算法原理, 我发现大家都知道小表驱动大表,要让小表作为驱动表, 现在有2个问题

  • 查询多表, 到底哪个是驱动表?哪个是被驱动表, 如何区分?
  • 索引如何优化,到底是加在驱动表上,还是被驱动表上? (答案是被驱动表!!!)

今天我们来讨论下这两个问题的答案

文章目录

      • Mysql实战-Join驱动表和被驱动表如何区分
        • 1.什么是驱动表和被驱动表?
        • 2.Explain命令区分 驱动表及被驱动表
        • 3. left join 左表可能不是驱动表
        • 4. left join 没where 查询 驱动表, 左表才是驱动表
        • 4. left join where 查询条件的表就是驱动表的错误说法
        • 5.left join where查询驱动表判断

1.什么是驱动表和被驱动表?

在join连接查询中,驱动表在SQL语句执行的过程中总是先被读取。而被驱动表在SQL语句执行的过程中总是后被读取。

在读取驱动表数据后,放入到join_buffer后,再去读取被驱动表中的数据来和驱动表中的数据进行匹配。如果匹配成功,就返回结果,否则该丢弃, 继续匹配下一条

为什么要小表驱动大表?
从上面的查询过程中,我们就知道了 , 因为小表查的少, 大大的减少了I/O 次数, join_buffer容量也有限, 表越小, 越少次数匹配, 越容易查结果,所以 我们必须区分 哪个是驱动表, 哪个是被驱动表

现在我们先创建2个表结构, 插入数据,作为测试数据

drop table user_info;
CREATE TABLE `user_info` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_name` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',`age` int(10)  DEFAULT NULL COMMENT '员工年龄',`address` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';drop table order_info;
CREATE TABLE `order_info` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`order_id` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单id',`user_id` bigint(20) NOT NULL COMMENT '用户user表主键id',
`goods` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '商品',
`production` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '产地',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表'INSERT INTO `order_info` (order_id, user_id, goods, production) VALUES (CONCAT("uuid",1), 2, "衣服", "上海贸易");#插入3条用户数据
INSERT INTO `user_info` (user_name, age, address) VALUES ("张三", 10, "北京");
INSERT INTO `user_info` (user_name, age, address) VALUES ("李四", 20, "上海");
INSERT INTO `user_info` (user_name, age, address) VALUES ("王五", 30, "广州");#插入2条 张三的 订单记录
INSERT INTO `order_info` (order_id, user_id, goods, production) VALUES ("uuid1", 1, "衣服", "北京三里屯");
INSERT INTO `order_info` (order_id, user_id, goods, production) VALUES ("uuid2", 1, "鞋子", "北京三里屯");
#插入1w条 李四的订单记录, 用存储过程执行#先创建存储过程
CREATE PROCEDURE test() #创建存储函数;
BEGIN
DECLARE i INT DEFAULT 100;WHILE i < 10100 DOINSERT INTO `order_info` (order_id, user_id, goods, production) VALUES (CONCAT("uuid",i), 2, "书本", "上海贸易");SET i = i+1;
end WHILE;END;
#然后执行 存储过程
CALL test();#调用存储函数

我们可以看下数据是否插入成功
user_info 3条数据
order_info 10002条数据
在这里插入图片描述

2.Explain命令区分 驱动表及被驱动表

对于已有的SQL语句,我们可以直接通过Explain 命令来判断 驱动表与被驱动表, explain命令查看一下SQL语句的执行计划。

输出的执行计划中,首先出现的排在第一行的表是驱动表,排在第二行的表是被驱动表,比如下面的语句

#查看驱动表 第一行就是驱动表
explain
select * from user_info 
left join order_info
on user_info.id = order_info.user_id;

查看执行结果

  • 第一行 user_info表 ,所以驱动表是 user_info
  • 第二行 order_info表, 被驱动表示 order_info
  • 此刻都没有索引信息, type=ALL
  • 即使双方连接字段是 id~user_id, user_info表的id是主键, user_info表也没有走索引
  • 所以驱动表有索引, 也不一定走
    在这里插入图片描述

这里虽然左表示 user_info 是驱动表, 而且是 left_join 查询, 那么我们可以得出结论 left join 左表一定是驱动表么 ?

不能, 重要事情说三遍
!!! left join 左表 不一定是驱动表
!!! left join 左表 不一定是驱动表
!!! left join 左表 不一定是驱动表

3. left join 左表可能不是驱动表

下面我们来验证下 left join 左表不是驱动表的逻辑

我们看下 下面的 查询语句, 也是用 left join 查询, 可以看到 左表是 order left join user_info
那么我们看下 explain 到底哪个是驱动表

#left join 左表不一定是 驱动表
explain
select * from order_info 
left join user_info
on user_info.id = order_info.user_id
where user_info.id = 1;

执行结果

  • left join 左表是 order_info
  • 但是 驱动表是user_info
  • 所以 并不是 left_join 左表就是驱动表
  • 同理 right_join 右表也不一定是驱动表
    在这里插入图片描述

那么 什么情况下? left join 左表示驱动表呢?

4. left join 没where 查询 驱动表, 左表才是驱动表

当SQL查询语句没有 where 查询条件时

  • 没有 where 查询条件时 left join 左表是驱动表, 右表是被驱动表
  • 没有 where 查询条件时 right join 右表是驱动表, 左表示被驱动表
  • 没有 where 查询条件时 inner join 也就是join, mysql自动选择 小表作为驱动表, 大表作为被驱动表,进行底层优化

先说结论, 下面我们验证下这个逻辑

  • 没有 where 查询条件时 left join 左表是order_info, explain 驱动表就是 order_info
  • 没有 where 查询条件时 left join 左表示驱动表, 不管查询表位置如何交换
  • 没有 where 查询条件时 join查询, 不管 左右表顺序, mysql自己优化选择小表作为驱动表

1.没有 where 查询条件时 left join 左表是order_info, explain 驱动表就是 order_info

#没where 查询 左表才是驱动表, 左表是order
explain
select * from order_info 
left join user_info
on user_info.id = order_info.user_id

执行结果, 符合预期
在这里插入图片描述

换下位置,看看是否 依旧如此
2.没有 where 查询条件时 left join 左表是user_info, explain 驱动表就是 user_info

#没where 查询  左表才是驱动表, 换位置 左表是userexplain
select * from user_info 
left join order_info
on order_info.user_id = user_info.id

执行结果, 符合预期
在这里插入图片描述
3.没有 where 查询条件时 , 不管 左右表顺序, join 驱动表是mysql自己优化选择的,小表 user_info就是驱动表, user_info 3条数据, order_info 1w多条数据

#join查询, mysql选择小表作为驱动表explain
select * from user_info 
left join order_info
on order_info.user_id = user_info.id#join'查询, 换下 user_info 和 order_info 的位置
explain
select * from order_info 
join user_info
on user_info.id = order_info.user_id 

user_info不论左侧右侧, 都是小表作为驱动表
执行结果 符合预期
在这里插入图片描述

4. left join where 查询条件的表就是驱动表的错误说法

有where 查询语句时, 驱动表的判断规则是另一种情况
有一种 说法 where查询中只有一个表结构, 那么该表就是驱动表 ?

这种说法是错误的,重要事情说三遍
!!! 有where查询的, where条件的表 就是驱动表 这是错误的
!!! 有where查询的, where条件的表 就是驱动表 这是错误的
!!! 有where查询的, where条件的表 就是驱动表 这是错误的

#带where 查询表, where的表 不是驱动表, 验证错误语法
explain
select * from user_info 
left join order_info
on user_info.id = order_info.user_id
where order_info.user_id = 1;

这是有where 查询条件的, 而且where查询中只有一个表 order_info, 我们来执行下 explain
执行结果, 有where查询条件, order_info,但是 explain的驱动表是 user_info表
在这里插入图片描述
所以上面的说法是靠不住的

5.left join where查询驱动表判断

上面我们验证了 where 查询表就是驱动表这种说法的错误性, 那么 带where查询条件到底哪个是驱动表呢?

我们先说结论,然后验证,结论如下

  • where 查询字段没索引, 那就是谁是左表,用谁
  • where 查询字段有索引, 那就用where表作为驱动表

1.where 查询表字段没索引, 谁是左表,用谁做驱动表
在这里插入图片描述

2.where 查询字段有索引, 那就用where表作为驱动表
在这里插入图片描述

到这里 我们已经了解了 join 语法驱动表及被驱动表的判断,现在回答下开始的问题

  • 1.查询多表, 到底哪个是驱动表?哪个是被驱动表, 如何区分?
    • 不同的查询语句对应不同的驱动表划分策略,比如没有where的查询,left join的查询,带where的查询,inner join的查询,及查询字段 都会影响驱动表的选择
  • 2.索引如何优化,到底是加在驱动表上,还是被驱动表上?
    • 我们直到查询要小表驱动大表, 对于小表驱动表来说 无论建立没建立索引,都需要全表扫描的
    • 所以我们要把索引建立再大表上, 也就是说 索引要建立在 被驱动表上
    • 如果大表在连接字段上建立了索引,就可以走索引,尽快的匹配出想要的数据

至此, 我们已经了解了 join 语法驱动表及被驱动表的判断,这对于我们进行SQL优化至关重要, 只有知道了被驱动表,我们才能进行针对索引进行优化,磨刀不误砍柴工

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

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

相关文章

初学编程入门基础教学视频,中文编程开发语言工具箱之豪华编辑构件,免费版中文编程软件下载

初学编程入门基础教学视频&#xff0c;中文编程开发语言工具箱之豪华编辑构件&#xff0c;免费版中文编程软件下载 构件的其中一个属性、方法&#xff0c;查找内容&#xff0c;替换内容。 构件工具箱非常丰富&#xff0c;其中该构件在 文本件构件板菜单下。 编程系统化课程总目…

C++类模板再学习

之前已经学习了C类模板&#xff1b;类模板的写法和一般类的写法有很大的差别&#xff1b;不容易熟悉&#xff1b;下面再做一遍&#xff1b; 做一个椭圆类&#xff0c;成员有长轴长度和短轴长度&#xff1b; // ellipse.h: interface for the ellipse class. // //#if !define…

李宏毅老师浅谈机器学习

李宏毅老师浅谈机器学习 引例 - 宝可梦/数码宝贝 分类器如何定义损失函数&#xff1f;- 经验这里定义一个直观的loss函数根据全体数据&#xff0c;得到最好的模型参数(理想&#xff09;如何衡量现实损失和理想损失接近程度&#xff1f;如何得到跟含所有样本数据集很像的取样数据…

MFC实现堆栈窗口:多个子界面可任意切换

1、效果 在Qt中可使用QStackedWidget控件直接拖动布置即可实现&#xff0c;但在MFC中并未提供类似的控件&#xff0c;因此需要自己简单实现。 2、实现原理 实现原理比较简单&#xff0c;父级对话框在显示的区域部分&#xff0c;通过切换子对话框即可实现。子对话框去掉边框后…

idea使用MyBatisX插件

1.MyBatisX功能 (1).实现mapper和xml的跳转 (2).自动生成java文件&#xff0c;比如mapper、service、dao、pojo 2.安装MyBatisX插件 install后然后重启idea即可 3.使用MyBatieX实现mapper和xml跳转 &#xff08;1&#xff09;.点击mapper中的红色图标即可跳转到对应的xml方…

一文告诉你样机是什么,分享几个常用的样机模板

一个项目的诞生通常需要经历头脑构思、绘制设计和最终着陆。在这个过程中&#xff0c;样机制作往往是在着陆实践之前进行的。俗话说&#xff1a;“样机使用得好&#xff0c;草稿过早”。样机设计是产品或网站最终设计的生动、静态和视觉表现。它为用户提供了一种模拟现实的方式…

腾讯云轻量应用服务器“月流量”不够用怎么办?

腾讯云轻量应用服务器“月流量”不够用怎么办&#xff1f;超额部分支付流量费&#xff0c;价格为0.8元/GB。腾讯云轻量服务器月流量什么意思&#xff1f;月流量是指轻量服务器限制每月流量的意思&#xff0c;不能肆无忌惮地使用公网&#xff0c;流量超额需要另外支付流量费&…

电子学会C/C++编程等级考试2023年05月(六级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:字符串插入 有两个字符串str和substr,str的字符个数不超过10,substr的字符个数为3。(字符个数不包括字符串结尾处的’\0’。)将substr插入到str中ASCII码最大的那个字符后面,若有多个最大则只考虑第一个。 时间限制:1000 …

Nginx性能优化

简介 nginx作为常用的web代理服务器&#xff0c;某些场景下对于性能要求还是蛮高的&#xff0c;所以本片文章会基于操作系统调度以及网络通信两个角度来讨论一下Nginx性能的优化思路。 基于操作系统调度进行Nginx优化 CPU工作方式 对于用户进程&#xff0c;CPU会按照下面的…

家政服务系统小程序app开发功能架构;

家政服务小程序系统&#xff0c;轻松搭建上门服务小程序。支持H5与小程序双端&#xff0c;还能DIY页面。根据您的需求&#xff0c;我们可定制开发家政服务小程序系统。想添加多种服务类目、优惠专区以及IM即时沟通功能&#xff1f;没问题&#xff0c;我们支持&#xff01;想要快…

uniapp保存网络图片

先执行下载uni.downloadFile接口&#xff0c;再执行保存图片uni.saveImageToPhotosAlbum接口。 // 保存二维码 saveQrcode() {var _this this;uni.downloadFile({url: _this.qrcodeUrl, //二维码网络图片的地址success(res) {console.log(res);uni.saveImageToPhotosAlbum({fi…

spring boot配置ssl(多cer格式)保姆级教程

1. 准备cer格式的证书&#xff1b; 2. 合并cer证书并转化成jks格式的证书 为啥有这一步&#xff0c;因为cer证书配置在spring boot项目中&#xff0c;项目启动不起来。如果有大佬想指导一下可以给我留言&#xff0c;在此先谢过大佬。 1&#xff09;先创建一个jks格式的证…

hack_me_please靶机攻略

hack_me_please 扫描 探查无果&#xff0c;扫描js的时候有结果 访问可以看到 该页面可以看到是SeedDMS搭的 应该和CMS类似 渗透 漏洞库查找一下有没有该漏洞 使用whatweb扫描一下刚才的页面 whatweb http://10.4.7.154/seeddms51x/seeddms-5.1.22/ 这个版本高于漏洞库的&a…

<学习笔记>从零开始自学Python-之-常用库篇(十三)内置小型数据库shelve

一、shelve简介&#xff1a; shelve是Python当中数据储存的方案&#xff0c;类似key-value数据库&#xff0c;便于保存Python对象&#xff0c;shelve只有一个open&#xff08;&#xff09;函数&#xff0c;用来打开指定的文件&#xff08;字典&#xff09;&#xff0c;会返回一…

从0到1之微信小程序快速入门(基础知识)

目录 JSON 配置文件 WXML 模板 WXSS 样式 JS 逻辑交互 微信小程序中&#xff0c;每个页面由4 个基本文件组成&#xff0c;它们分别是&#xff1a;js文件(页面的脚本文件&#xff0c;存放页面的数据、事件处理函数等)、json文件(当前页面的配置文件&#xff0c;配置窗口的外…

excel技巧

excel技巧 &#x1f353;选中&#x1f353;填充&#x1f353;日期&#x1f352;&#x1f352; 日期快捷方式&#x1f352;&#x1f352; 日期计算&#x1f352;&#x1f352;时间相减 &#x1f353;求和&#x1f353;去除小数点&#x1f353;美化表格&#x1f352;&#x1f352…

Kubernetes Service 详解

Author&#xff1a;rab 目录 前言一、ClusterIP1.1 简介1.2 案例 二、NodePort2.1 简介2.2 案例 三、LoadBalancer3.1 简介3.1.1 MetalLB 简介3.1.2 MetalLB 部署3.1.3 MetalLB 配置3.1.3.1 Layer 2 模式3.1.3.2 BGP 模式 3.2 案例3.2.1 部署3.2.2 验证 四、ExternalName4.1 简…

计算机视觉 激光雷达结合无监督学习进行物体检测的工作原理

一、简述 激光雷达是目前正在改变世界的传感器。它集成在自动驾驶汽车、自主无人机、机器人、卫星、火箭等中。该传感器使用激光束了解世界,并测量激光击中目标返回所需的时间,输出是点云信息,利用这些信息,我们可以从3D点云中查找障碍物。 从自动驾驶汽车的角度看激光雷达…

【PyQt学习篇 · ②】:QObject - 神奇的对象管理工具

文章目录 QObject介绍Object的继承结构测试QObject对象名称和属性QObject对象名称和属性的操作应用场景 QObject父子对象QObject父子对象的操作 QObject的信号与槽QObject的信号与槽的操作 QObject介绍 在PyQt中&#xff0c;QObject是Qt框架的核心对象之一。QObject是一个基类…

长图切图怎么切

用PS的切片工具 切片工具——基于参考线的切片——ctrl&#xff0b;shift&#xff0b;s 过长的图片怎么切 ctrl&#xff0b;alt&#xff0b;i 查看图片的长宽看图片的长宽来切成两个板块&#xff08;尽量中间切成两半&#xff09;用选区工具选中下半部分的区域——在选完时不…