mysql 多表怎么连接的

news/2025/3/20 18:39:17/文章来源:https://www.cnblogs.com/aoximin/p/18783712

前言

简单描述一下多表怎么连接的。

正文

首先,我们得抛开我们一些自以为是的想法。

我想过这个问题,就是为什么我们背乘法口诀的时候,我们总是背:

22 = 4, 99=81 这样背下去,似乎这是口诀。然而这是缓存,不是计算,既然不是计算那么就不是逻辑学。

我们理所当然的想9*9=81,而抛弃了运算过程。

这样短期是有好处的,那就是我们马上知道99=81,这似乎是好处,那么坏处是啥,那就是我们抛弃了本质问题,为什么99的计算过程。

而计算机就是描述计算过程的机器。

比方说,我们在多表连接的时候就会想,怎么怎么去实现它。

比如select * from t1,t2 where t1.id= t2.t1Id and t1.a > 50 and t2.b > 20

我们会去想如何能够让计算机快速得出我们的答案呢。

我们肯定会想,同时进行是不是很好呢?比如说把t1.a >50 的找出来,同时按照t2.b >20 的找出来。

然后进行在根据条件t1.id= t2.t1Id 进行条件拼接。

是的,是的,我们这个时候又会想如果一个一个区遍历t1的结果,然后每一个去找到t2的结果似乎很慢,如何能减少遍历次数呢?

是的,是的,没错,我们脑海中第一印象就是想着如何如何去优化。而且是否我们最开始的优化想法,是否是优化的呢?

比如说把t1.a >50 的找出来,同时按照t2.b >20 的找出来,这个是否同时做就是优化呢?

先来看一下最最最简单的实现,一切都是串行, 简单的逻辑去思考问题。

第一步呢,我们首先查出t1.a>50 条的出来,比如说有两条,比如a=51和a=52,id 是10和15

那么可以根据这两条,去b中查询。

b 中怎么查询呢? b的查询方式是t1.a = t2.b查询。

比如第一条,id 是10,那么就查询t2中t1Id为10的,查出来后再根据t2.b >20进行过滤。

第二条同理。

也就是说在两表连接查询中,驱动表只需要访问一次,被驱动表可能被访问多次。

这似乎是可以实现我们的东西,对于人来说似乎是复杂的,但是对于机器而言会不厌其烦。

这里有个问题,那就是我们以t1为驱动表,那么为啥是t1呢? 有没有可能是t2呢?

嗯,似乎是可以的。假如t2.b >20只查出一条的话,那么是不是性能更高呢。

似乎t1还是t2做驱动表似乎是可以根据一些参数做一些优化的。

但是是不是全部的连接,都可以根据参数去做优化的呢?

其实只有内连接系统可以自我去优化。

除了内连接还有外连接呢。

那么什么是外连接呢? 请百度。

外连接如果是左连接,那么就是左边的作为驱动表,如果是右连接就右边的作为驱动表。

如果你了解什么是外连接的,那么这样实现是没有问题的。

现在想想该怎么优化呢?

第一阶段我们查询t1,似乎我们没有啥好优化的,那么能不能从第二阶段下文章呢?

第二阶段我们可以分成两条语句。

select * from t2 where t2.t1Id = 20 and t2.b> 20select * from t2 where t2.t1Id = 30 and t2.b> 20

对于t2的查询,那么我们似乎可以创建索引。这也是为啥我们外键会创建索引。

假如我们t1Id创建索引的话,那么是不是就很快了。

然要并非一定要如此,t2.b 创建也是可以的,只是这会条件就是t2.t1Id = 20了。

然后我们知道t2.t1Id = 20 如果是唯一索引或者说是主键索引,那么就是查询方式是const,但是如果作为被驱动表,那么名字就叫做eq_ref了。

另外,有时候连接查询的查询列表和过滤条件中可能只涉及被驱动表的部分列,而这些列都是某个索引的一部
分,这种情况下即使不能使用 eq_ref 、 ref 、 ref_or_null 或者 range 这些访问方法执行对被驱动表的查询的
话,也可以使用索引扫描,也就是 index 的访问方法来查询被驱动表。所以我们建议在真实工作中最好不要使
用 * 作为查询列表,最好把真实用到的列作为查询列表。

那么还有没有其他可以优化的地方呢?

这里我们知道,我们查询出来一条就要和驱动表匹配一次,这似乎有点点不太如意。

这有索引的情况下,其实还好,但是如果没有索引呢?那么我们是不是得去全表扫描。

如果一条驱动表的记录扫描一次,那么如果很多很多呢?那么不是得扫描很多很多次。

这似乎很糟糕。

那么如何才能不那么糟糕呢? 那就是批量取呗。

当被驱动表中的数据非常多时,每次访问被驱动表,被驱动表的记录会被加载到内存中,在内存中的每一条记录
只会和驱动表结果集的一条记录做匹配,之后就会被从内存中清除掉。然后再从驱动表结果集中拿出另一条记
录,再一次把被驱动表的记录加载到内存中一遍,周而复始,驱动表结果集中有多少条记录,就得把被驱动表从
磁盘上加载到内存中多少次。所以我们可不可以在把被驱动表的记录加载到内存的时候,一次性和多条驱动表中
的记录做匹配,这样就可以大大减少重复从磁盘上加载被驱动表的代价了。所以设计 MySQL 的大叔提出了一个
join buffer 的概念, join buffer 就是执行连接查询前申请的一块固定大小的内存,先把若干条驱动表结果集
中的记录装在这个 join buffer 中,然后开始扫描被驱动表,每一条被驱动表的记录一次性和 join buffer 中的
多条驱动表记录做匹配,因为匹配的过程都是在内存中完成的,所以这样可以显著减少被驱动表的 I/O 代价。使
用 join buffer 的过程如下图所示:

最好的情况是 join buffer 足够大,能容纳驱动表结果集中的所有记录,这样只需要访问一次被驱动表就可以完
成连接操作了。设计 MySQL 的大叔把这种加入了 join buffer 的嵌套循环连接算法称之为 基于块的嵌套连接
(Block Nested-Loop Join)算法。

这个 join buffer 的大小是可以通过启动参数或者系统变量 join_buffer_size 进行配置,默认大小为 262144字
节 (也就是 256KB ),最小可以设置为 128字节 。当然,对于优化被驱动表的查询来说,最好是为被驱动表加
上效率高的索引,如果实在不能使用索引,并且自己的机器的内存也比较大可以尝试调大 join_buffer_size 的
值来对连接查询进行优化。
另外需要注意的是,驱动表的记录并不是所有列都会被放到 join buffer 中,只有查询列表中的列和过滤条件中
的列才会被放到 join buffer 中,所以再次提醒我们,最好不要把 * 作为查询列表,只需要把我们关心的列放到
查询列表就好了,这样还可以在 join buffer 中放置更多的记录呢哈。

其实最好还是避免全表扫描,建立对应的索引更好,尽量不要用到block nested-loop join.

简单介绍一下连接的原理。

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

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

相关文章

202108120808 - 类加载器及双亲委派机制

Bootstrap ClassLoader 这是加载器中的大 Boss,任何类的加载行为,都要经它过问。它的作用是加载核心类库,也就是 rt.jar、resources.jar、charsets.jar 等。当然这些 jar 包的路径是可以指定的,-Xbootclasspath 参数可以完成指定操作。 这个加载器是 C++ 编写的,随着 JVM …

keil仿真时导出数据操作

keil仿真时导出数据操作 save D:\savedata.txt 0x20001013,0x20001035

spring-boot-starter-validation

官方提供的注解 spring-boot-starter-validation 是 Spring Boot 提供的一个 starter,是一个用于验证 Java Bean 的标准,它提供了一套注解和相应的运行时 API 来定义和执行校验规则。 具体来说,当你在项目中引入 spring-boot-starter-validation 后,你可以使用一系列预定义…

省选算法复习

省选算法复习 1. 线段树优化建图 当我们需要向区间内所有点连边或者从区间中所有点连到某个点的时候,便可以使用线段树来优化,如果需要从区间每一个点连到另一个区间每一个点的话,加一个虚点就好了。 这不是一个很困难的技巧,关键在于要建模。 P5471 [NOI2019] 弹跳 - 洛谷…

fastadmin订单父子表管理端

fastadmin后台父子表使用方法 发布于 2021-01-22 12:48:10fastadmin后台的所有表格都是支持父子表配置的,只需要简单修改一下对应的JS即可,下面直接进入主题。示例是我的全国省市行政区划表,是从国家统计局网站采集下来的,共五级行政数据,非常适合用来做父子表,按照级别一…

Rudolf and k Bridges

Rudolf and k Bridges 题目 大致题意上图为俯视图 有一个\(nXm\)的网格,下标从\(1-n\) 以及从 \(1-m\),\((i, j)\) 的值就是这个这垂直一格水的深度 现在要安装支架,有几个信息:\((i, 1)\) 和 \((i, m)\) 处必须要安装相邻支架的距离不能超过 \(d\), 相邻距离为 \(abs(j - …

背离Divergence Trading ,贪小便宜

趋势交易(trend trading)和背离交易(divergence trading),代表了两种不同的交易策略。做背离交易相当于赌市场短期失效,承认你比市场聪明,虽然能赚小钱,但往往是亏大钱的根源。 贪小便宜爱背离,贪小便宜(gain small advantages)不爱止损(cut losses),所以背离和不止损…

在鸿蒙NEXT开发中实现一个语音识别组件

鸿蒙系统发布以后都不知道叫它5.0版本还是NEXT版本了,哈哈,反正是最新版本就对了。对于语音转换文字,鸿蒙系统提供了离线语音识别模型speechRecognizer,语种目前支持中文,识别效果非常不错。今天要分享的是使用speechRecognizer实现一个语音识别组件。要实现语音识别,首先…

激光代加工产品一览-代加工-外协加工-委外加工-激光代加工-河南郑州亚克力切割雕刻代加工-芯晨微纳(河南)

关键词:河南省郑州市、激光代加工、激光打标、激光切割、激光雕刻、激光打孔、激光毛化、激光分切 简介:芯晨微纳(河南)光电科技有限公司,专注于激光微纳代加工、设备/耗材代理销售、设备租赁、技术推广服务,可处理材料类型及应用范围十分广泛,欢迎来电咨询(韩经理1823…

20242801 2024-2025-2 《网络攻防实践》第4次作业

20242801 2024-2025-2 《网络攻防实践》第4次作业 一、实验内容 ​ 在虚拟机环境中完成TCP/IP协议栈重点协议的攻击实验,学习ARP缓存欺骗攻击、ICMP重定向攻击、SYN Flood攻击、TCP RST攻击、TCP会话劫持攻击的原理和相关知识,并动手进行实践。 二、实验过程 (一)ARP缓存欺…

缓存监控治理在游戏业务的实践和探索

通过对 Redis 和 Caffeine 的缓存监控快速发现和定位问题降低故障的影响面。作者:来自 vivo 互联网服务器团队- Wang Zhi 通过对 Redis 和 Caffeine 的缓存监控快速发现和定位问题降低故障的影响面。 一、缓存监控的背景游戏业务中存在大量的高频请求尤其是对热门游戏而言,而…

从零开始驯服Linux(一):ZYNQ-Linux启动文件构建全解析

从零开始驯服Linux(一):ZYNQ-Linux启动文件构建全解析 ZYNQ系列芯片集成了ARM处理器和FPGA(可编程逻辑单元),正是因为由于ARM处理器的存在,所以我们可以在ZYNQ系列芯片上面运行Linux系统。 在ZYNQ系列芯片上运行Linux会给我们带来很多优势:首先,我们可以将部分逻辑处理…