mysql - 多表访问

多表访问

创建两个表

mysql> SELECT * FROM t1;
+------+------+
| m1   | n1   |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
+------+------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM t2;
+------+------+
| m2   | n2   |
+------+------+
|    2 | b    |
|    3 | c    |
|    4 | d    |
+------+------+
3 rows in set (0.00 sec)

连接的本质就是笛卡尔积

mysql> SELECT * FROM t1, t2;
+------+------+------+------+
| m1   | n1   | m2   | n2   |
+------+------+------+------+
|    1 | a    |    2 | b    |
|    2 | b    |    2 | b    |
|    3 | c    |    2 | b    |
|    1 | a    |    3 | c    |
|    2 | b    |    3 | c    |
|    3 | c    |    3 | c    |
|    1 | a    |    4 | d    |
|    2 | b    |    4 | d    |
|    3 | c    |    4 | d    |
+------+------+------+------+
9 rows in set (0.00 sec)

连接过程

多表连接时都会将表分为驱动表和被取代表,将驱动表过滤后的数据与被驱动表连接

SELECT * FROM t1, t2 WHERE t1.m1 > 1 AND t1.m1 = t2.m2 AND t2.n2 < 'd';

image_1ctrsprar1bbh17lee79le63ls2m.png-49.6kB

连接有内连接和外连接,为了分清两种连接,我们选建立两个表

mysql> SELECT * FROM student;
+----------+-----------+--------------------------+
| number   | name      | major                    |
+----------+-----------+--------------------------+
| 20180101 | 杜子腾    | 软件学院                 |
| 20180102 | 范统      | 计算机科学与工程         |
| 20180103 | 史珍香    | 计算机科学与工程         |
+----------+-----------+--------------------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM score;
+----------+-----------------------------+-------+
| number   | subject                     | score |
+----------+-----------------------------+-------+
| 20180101 | 母猪的产后护理              |    78 |
| 20180101 | 论萨达姆的战争准备          |    88 |
| 20180102 | 论萨达姆的战争准备          |    98 |
| 20180102 | 母猪的产后护理              |   100 |
+----------+-----------------------------+-------+
4 rows in set (0.00 sec)

内连接

mysql> SELECT * FROM student, score WHERE student.number = score.number;
+----------+-----------+--------------------------+----------+-----------------------------+-------+
| number   | name      | major                    | number   | subject                     | score |
+----------+-----------+--------------------------+----------+-----------------------------+-------+
| 20180101 | 杜子腾    | 软件学院                 | 20180101 | 母猪的产后护理              |    78 |
| 20180101 | 杜子腾    | 软件学院                 | 20180101 | 论萨达姆的战争准备          |    88 |
| 20180102 | 范统      | 计算机科学与工程         | 20180102 | 论萨达姆的战争准备          |    98 |
| 20180102 | 范统      | 计算机科学与工程         | 20180102 | 母猪的产后护理              |   100 |
+----------+-----------+--------------------------+----------+-----------------------------+-------+
4 rows in set (0.00 sec)

有没有发现成绩中没有史珍香的名字?

驱动表中的记录即使在被驱动表中若没有匹配的记录,就不会返回结果。为了解决这个问题,就有了内连接外连接的概念:

  • 对于内连接的两个表,驱动表中的记录在被驱动表中找不到匹配的记录,该记录不会加入到最后的结果集,我们上边提到的连接都是所谓的内连接
  • 对于外连接的两个表,驱动表中的记录即使在被驱动表中没有匹配的记录,也仍然需要加入到结果集。

外连接

MySQL中,根据选取驱动表的不同,外连接仍然可以细分为2种:

  • 左外连接

    选取左侧的表为驱动表。

  • 右外连接

    选取右侧的表为驱动表。

可是这样仍然存在问题,即使对于外连接来说,有时候我们也并不想把驱动表的全部记录都加入到最后的结果集。这就犯难了,有时候匹配失败要加入结果集,有时候又不要加入结果集,这咋办,有点儿愁啊。。。噫,把过滤条件分为两种不就解决了这个问题了么,所以放在不同地方的过滤条件是有不同语义的:

  • WHERE子句中的过滤条件

    WHERE子句中的过滤条件就是我们平时见的那种,不论是内连接还是外连接,凡是不符合WHERE子句中的过滤条件的记录都不会被加入最后的结果集。

  • ON子句中的过滤条件

    对于外连接的驱动表的记录来说,如果无法在被驱动表中找到匹配ON子句中的过滤条件的记录,那么该记录仍然会被加入到结果集中,对应的被驱动表记录的各个字段使用NULL值填充。

mysql> SELECT s1.number, s1.name, s2.subject, s2.score FROM student AS s1 LEFT JOIN score AS s2 ON s1.number = s2.number;
+----------+-----------+-----------------------------+-------+
| number   | name      | subject                     | score |
+----------+-----------+-----------------------------+-------+
| 20180101 | 杜子腾    | 母猪的产后护理              |    78 |
| 20180101 | 杜子腾    | 论萨达姆的战争准备          |    88 |
| 20180102 | 范统      | 论萨达姆的战争准备          |    98 |
| 20180102 | 范统      | 母猪的产后护理              |   100 |
| 20180103 | 史珍香    | NULL                        |  NULL |
+----------+-----------+-----------------------------+-------+
5 rows in set (0.04 sec)

连接算法

嵌套循环连接

对于两表连接来说,驱动表只会被访问一遍,但被驱动表却要被访问到好多遍,具体访问几遍取决于对驱动表执行单表查询后的结果集中的记录条数。对于内连接来说,选取哪个表为驱动表都没关系,而外连接的驱动表是固定的,也就是说左(外)连接的驱动表就是左边的那个表,右(外)连接的驱动表就是右边的那个表。

  • 步骤1:选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单表访问方法来执行对驱动表的单表查询。
  • 步骤2:对上一步骤中查询驱动表得到的结果集中每一条记录,都分别到被驱动表中查找匹配的记录。

通用的两表连接过程如下图所示:

image_1ctsr5ui2cdk1jduqafm7p1d3426.png-129.4kB

如果有3个表进行连接的话,那么步骤2中得到的结果集就像是新的驱动表,然后第三个表就成为了被驱动表,重复上边过程,也就是步骤2中得到的结果集中的每一条记录都需要到t3表中找一找有没有匹配的记录,用伪代码表示一下这个过程就是这样:

for each row in t1 {   #此处表示遍历满足对t1单表查询结果集中的每一条记录
    
    for each row in t2 {   #此处表示对于某条t1表的记录来说,遍历满足对t2单表查询结果集中的每一条记录
    
        for each row in t3 {   #此处表示对于某条t1和t2表的记录组合来说,对t3表进行单表查询
            if row satisfies join conditions, send to client
        }
    }
}

这个过程就像是一个嵌套的循环,所以这种驱动表只访问一次,但被驱动表却可能被多次访问,访问次数取决于对驱动表执行单表查询后的结果集中的记录条数的连接执行方式称之为嵌套循环连接Nested-Loop Join),这是最简单,也是最笨拙的一种连接查询算法。

基于块的嵌套循环连接

扫描一个表的过程其实是先把这个表从磁盘上加载到内存中,然后从内存中比较匹配条件是否满足。现实生活中的表可不像t1t2这种只有3条记录,成千上万条记录都是少的,几百万、几千万甚至几亿条记录的表到处都是。内存里可能并不能完全存放的下表中所有的记录,所以在扫描表前边记录的时候后边的记录可能还在磁盘上,等扫描到后边记录的时候可能内存不足,所以需要把前边的记录从内存中释放掉。我们前边又说过,采用嵌套循环连接算法的两表连接过程中,被驱动表可是要被访问好多次的,如果这个被驱动表中的数据特别多而且不能使用索引进行访问,那就相当于要从磁盘上读好几次这个表,这个I/O代价就非常大了,所以我们得想办法:尽量减少访问被驱动表的次数。

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

image_1ctuhe3t71ahd10gn19917fo1nft4g.png-57.7kB

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IP地址的分配:数字世界的地址规划者

在互联网的世界里&#xff0c;IP地址扮演着类似于房屋地址的角色&#xff0c;是用于标识和定位互联网上每个连接到网络的设备的唯一标识符。然而&#xff0c;这些IP地址并非随意分配&#xff0c;而是经过精心规划和管理的。本文将探讨IP地址的分配方式&#xff0c;揭示数字世界…

婴儿洗衣机十大排名名牌:十款超高价值婴儿洗衣机综合整理

我们都知道宝宝的皮肤是超级娇嫩的&#xff0c;宝宝的衣物也一样&#xff0c;宝宝的衣物大部分都是纯棉的。如果将宝宝的衣物和大人衣服一起扔进大型洗衣机混洗&#xff0c;更可能出现细菌交叉感染&#xff0c;对小宝宝来说百害而无一利&#xff0c;会让小宝宝肌肤过敏、红肿、…

有关Theano和PyTensor库

根据Github里面的介绍&#xff0c;PyTensor是源于Theano&#xff0c; Theano目前应该已经不再开发了&#xff0c;更新都是很多年前。 因此PyTensor在背景介绍中说 PyTensor is a fork of Aesara, which is a fork of Theano. Theano和PyTensor都是计算相关的库&#xff0c;可以…

【C语言】结构体类型名、变量名以及typedef

文章目录 分类判断结构体成员的使用typedef 分类判断 struct tag {char m;int i; }p;假设定义了上面这一个结构体&#xff0c;tag 就是类型名&#xff0c; p 就是变量名&#xff0c; m 和 i 就是结构体成员列表。 可以这么记&#xff0c;括号前面的是类型名&#xff0c;括号后…

2024年超声波清洗机选购攻略,高性价超声波清洗机推荐,看这篇就够

随着科技的飞速发展和生活品质的逐步提升&#xff0c;超声波清洗机已经成为了现代家庭不可或缺的清洁工具。它以独特的超声波清洁技术&#xff0c;能够深入物品的微小缝隙&#xff0c;有效去除污垢和细菌&#xff0c;为用户提供一种安全、高效且环保的清洁解决方案。2024年&…

处理器方法的参数

处理器方法的参数&#xff1a; 处理器方法可以包含以下四类参数&#xff0c;这些参数会在系统调用时由系统自动赋值&#xff0c;即程序员可在方法内直接使用: HttpServletRequestHttpServletResponseHttpSession请求中所携带的请求参数 控制器方法&#xff1a; 前面三个参数怎…

Android 系统源码快速入门

Android源码快速入门 今天分享的内容是Android源码快速入门&#xff0c;主要分为以下几个步骤&#xff1a; * 硬件要求 * 虚拟机安装 * 开发环境搭建 * 下载编译源码 * 从一个简单的实际开发需求体验 Framework 开发硬件要求 用于 Android Framework 开发的电脑需要较强的 C…

黑平台避雷!3月上半月FX110曝光68家,无监管成常态

黑平台层出不穷&#xff0c;反诈骗是一场长期的斗争。以半个月为周期&#xff0c;FX110网对虚假交易商进行常态化曝光&#xff0c;极力压缩黑平台的生存空间&#xff0c;减少骗局的发生。 3月上半月&#xff0c;FX110网再曝光黑平台68家&#xff0c;此次曝光的黑平台大都对监管…

深入探究process.env.NODE_ENV如何区分环境

公众号&#xff1a;程序员白特&#xff0c;欢迎一起学习交流~ 通常我们在开发中需要区分当前代码的运行环境是dev、test、prod环境&#xff0c;以便我们进行相对应的项目配置&#xff0c;比如是否开启sourceMap&#xff0c;api地址切换等。 而我们区分环境一般都是通过process.…

02_设计模式

文章目录 设计模式设计模式分类UML类图设计模式的原则 常用设计模式创建型设计模式单例设计模式饿汉模式懒汉模式&#xff08;线程不安全&#xff09;懒汉模式&#xff08;线程安全&#xff09;- Synchronized懒汉模式&#xff08;线程安全&#xff09;- Double Check懒汉模式&…

mysql不等于<>取特定值反向条件的时候字段有null值或空值读取不到数据

#小李子9479# 有如下的数据结构 &#xff0c;st_dl tinyint(4)&#xff0c;想从中读取不等于1的数据 于是写了一个sql语句 select * from tbname where st_dl<>1 返回数据为0。 修改一下 select * from tbname where IFNULL(st_dl,0)<>1 正确返回数据 IFNUL…

【深度学习与神经网络】MNIST手写数字识别1

简单的全连接层 导入相应库 import torch import numpy as np from torch import nn,optim from torch.autograd import Variable import matplotlib.pyplot as plt from torchvision import datasets, transforms from torch.utils.data import DataLoader读入数据并转为ten…

深度学习之本地部署大模型ChatGLM3-6B【大模型】【报错】

文章目录 0.前言1.模型下载2.配置环境2.1 下载项目文件2.2 配置环境 3.开始推理4.总结 0.前言 本博客将介绍ChatGLM3-6B大模型在Ubuntu上的本地部署教程 1.模型下载 由于毛毛张的服务器服务无法科学上网&#xff0c;所以模型的相关文件必须现在本地下载好&#xff0c;再上传到…

【ai技术】(1):发现一个大模型可视化项目,使用nodejs编写的,llm-viz,可以本地运行展示大模型结构。

1&#xff0c;关于项目 https://www.bilibili.com/video/BV1eF4m1c7NC/ 【ai技术】&#xff08;1&#xff09;&#xff1a;发现一个大模型可视化项目&#xff0c;使用nodejs编写的&#xff0c;llm-viz&#xff0c;可以本地运行展示大模型结构。 https://github.com/bbycroft/l…

k8s集群架构维护k8s集群以及搭建k8s集群以及k8s集群的常见问题

一、k8s架构 Kubernetes&#xff08;K8s&#xff09;是一个由Google主导开发的开源容器编排平台&#xff0c;用于自动化部署、扩展和管理容器化应用程序。它的设计目标是简化容器化应用程序在生产环境中的部署和运营。Kubernetes的架构设计复杂且高效&#xff0c;主要包括以下几…

再谈EMC Unity存储系统内存DIMM问题

以前写过一篇关于EMC Unity 存储系统的DIMM的介绍文章&#xff0c;但是最近还是遇到很多关于内存的问题&#xff0c;还有一些退货&#xff0c;所以有必要再写一篇关于EMC Unity 内存方面的问题&#xff0c;供朋友们参考。如果还有疑问&#xff0c;可以加vx&#xff1a;StorageE…

v-bind 绑定 class 与 style 基础用法

使用 v-bind 指令绑定 class 和 style 时语法相对复杂一些&#xff0c;这两者是可以互相替代的&#xff0c;均用于响应更新HTML元素的属性&#xff0c; v-bind 绑定 class 属性可以改写成绑定 style 属性&#xff0c;只是 css 属性位置变了而已。 1. 绑定 class 属性 1.1 数组…

MySQL 数据库设计范式

第一范式&#xff08;1NF&#xff09; 每一列都是不可分割的原子数据项第二范式&#xff08;2NF&#xff09; 在1NF的基础上&#xff0c;非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖) 1.函数依赖A->B&#xff0c;如果通过A属性(属性组)的值…

蓝桥杯 2023 省B 飞机降落

首先&#xff0c;这题要求的数据量比较少&#xff0c;我们可以考虑考虑暴力解法。 这题可能难在很多情况的考虑&#xff0c;比如说&#xff1a; 现在时间是10&#xff0c;有个飞机20才到&#xff0c;我们是可以干等10分钟。 #include <iostream> #include <…

编织效率之梦:Visual Studio与Windows快捷键指南

个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 前言&#xff1a; 常用快捷键整理 (用加粗标注的是我个人使用时常用的&#xff0c;其实这个…