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

news2024/11/16 7:56:44

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 DO
	INSERT 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 查询  左表才是驱动表, 换位置 左表是user
 explain
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.coloradmin.cn/o/1152371.html

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

相关文章

UDP网络编程的接受与发送信息

/发送端B>可以接受数据 public class UDPSenderB {public static void main(String[] args) throws IOException {//创建一个DatagramSocket 对象&#xff0c;准备发送和接受数据DatagramSocket socket new DatagramSocket(9998);//将需要发送的数据&#xff0c;封装到Data…

在excel中如何打出上标、下标

例如&#xff0c;想把A2的2变为下标。 在单元中输入内容&#xff1a; 选中2&#xff1a; 右键单击&#xff0c;然后点击“设置单元格格式”&#xff1a; 在特殊效果的下面勾选“下标”&#xff0c;然后点击下面的“确定”按钮&#xff1a; 就将2变为下标了&#xff1a;…

HTML标题、段落、文本格式化

HTML标题&#xff1a; 在HTML文档中&#xff0c;标题是很重要的。标题是通过<h1> - <h6标签进行定义的&#xff0c;<h1> 定义最大的标题&#xff1b;<h6>定义最小的标题。 <hr> 标签在HTML页面中用于创建水平线&#xff0c;hr元素可用于分隔内容。…

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

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

测试用例设计——WEB通用测试用例

现在项目做完了&#xff0c;我觉得还是有必要总结一下&#xff0c;学习到的内容。毕竟有总结才能有提高嘛&#xff01;总结一下通用的东西&#xff0c;不管什么项目基本都可能会遇到&#xff0c;有写地方也有重复的或者有的是按照个人的习惯来总结的不一定都对&#xff0c;有不…

数据结构(超详细讲解!!)第十八节 串(静态存储)

1.串的定义 串&#xff1a;由零个或多个字符组成的有限序列&#xff0c;一般记为&#xff1a;s“a1a2...an” (n≥0)。 ai可以是字母、数字或其他字符。 串中字符的个数n称为串的长度。 空串&#xff1a;零个字符&#xff0c;即长度为零的串称为空串&#xff0c;用或””表…

Python爬虫实战案例——第七例

文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff01;严禁将文中内容用于任何商业与非法用途&#xff0c;由此产生的一切后果与作者无关。若有侵权&#xff0c;请联系删除。 目标&#xff1a;LI视频采集 地址&#xff1a;aHR0cHM6Ly93d3cucGVhcnZpZGVv…

2023最新最全Web自动化测试面试题

1、Selenium 中 hidden 或者是 display none 的元素是否可以定位到&#xff1f; 不可以。可以写 JavaScript 将标签中的 hidden 先改为 0&#xff0c;再进行定位元素。 2、Selenium 中如何保证操作元素的成功率&#xff1f;也就是说如何保证我点击的元素一 定是可以点击的&am…

Redis的特性和应用场景

目录 Redis的特性 内存存储数据 可编程性 可扩展性 持久化 水平扩展性 高可用性 为什么redis是快的 Redis的应用场景 数据库 缓存和会话存储 消息队列 redis是一个客户端服务器结构的程序 Redis是一个在内存中存储数据的中间件,能够用于作为数据库,数据缓存等,能在…

leetcode-字符串

1.反转字符串LeetCode344. 20230911 难度为0&#xff0c;此处就不放代码了 注意reverse和swap等一系列字符串函数什么时候该用&#xff0c;记一记库函数 swap可以有两种实现&#xff0c;涨知识了&#xff0c;除了temp存值还可以通过位运算&#xff1a;s[i] ^ s[j]; s[j] ^ s[i…

使用electron创建桌面应用及常见打包错误解决

一、基本要求 在使用Electron进行开发之前&#xff0c;您需要安装 Node.js。 要检查 Node.js 是否正确安装&#xff0c;请在您的终端输入以下命令&#xff1a; node -v npm -v这两个命令应输出了 Node.js 和 npm 的版本信息。 二、创建应用 1、首先创建一个文件夹 mkdir …

C++项目——云备份-⑨-服务端与客户端功能联调

文章目录 专栏导读1.服务端源代码2.客户端源代码3.浏览器访问测试//listshow 4.上传文件测试5.文件下载测试 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&#xff0c;阿里云专家博主&…

基于黄金正弦算法的无人机航迹规划-附代码

基于黄金正弦算法的无人机航迹规划 文章目录 基于黄金正弦算法的无人机航迹规划1.黄金正弦搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用黄金正弦算法来优化无人机航迹规划。 …

NumPy教程(快速入门版)

NumPy 是基于Python的数学计算库&#xff0c;擅长处理数组/矩阵。 NumPy 是 Numerical Python 的缩写&#xff0c;它是一个由多维数组对象&#xff08;ndarray&#xff09;和处理这些数组的函数&#xff08;function&#xff09;集合组成的库。使用 NumPy 库&#xff0c;可以对…

修仙路上的基石->java内置的占位符

java内的占位符 System.out.println(String.format("牛逼logger记录:%s",message)); 在 Java 中&#xff0c;%s 是一个格式化字符串的占位符&#xff0c;用于表示后续参数中的字符串值。在 String.format() 方法中&#xff0c;%s 会被替换为相应的参数值。在给定的例…

Ubuntu 搭建 DHCP ivp6 server 步骤

Ubuntu 搭建 DHCP ivp6 server 步骤 安装 DHCP server安装 radvd&#xff08;实现局域网路由功能)测试运行 安装 DHCP server apt 安装 isc-dhcp-server sudo apt-get install isc-dhcp-server修改配置文件 /etc/dhcp/dhcpd6.conf 内容如下&#xff1a; lease-time 7200; lo…

chatgpt生成文本的底层工作原理是什么?

文章目录 &#x1f31f; ChatGPT生成文本的底层工作原理&#x1f34a; 一、数据预处理&#x1f34a; 二、模型结构&#x1f34a; 三、模型训练&#x1f34a; 四、文本生成&#x1f34a; 总结 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN…

四十一、【进阶】索引使用SQL提示

1、SQL提示使用情景 在使用MySQL时&#xff0c;当一个字段参在于多个索引中时&#xff0c;默认情况下&#xff0c;MySQL会自动选择一个索引&#xff0c;但我们可以指定索引吗&#xff1f;可以忽略某一种索引吗&#xff1f; 答案是可以的。 前提&#xff1a;profession字段已经…

算法通关村第四关-黄金挑战栈的经典问题

括号匹配问题 描述 : 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有…

【Linux】内存精讲

TOC 目录 程序在计算机中的运行方式 CPU的指令 虚拟内存是什么&#xff1f; CPU的数据处理能力 &#xff08;1&#xff09;16位CPU &#xff08;2&#xff09;32位CPU &#xff08;3&#xff09;64位CPU 编译模式 32位编译模式 64位编译模式 C语言内存对齐 内存分…