MySQL两个表的亲密接触-连接查询的原理

这篇具有很好参考价值的文章主要介绍了MySQL两个表的亲密接触-连接查询的原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

MySQL对于被驱动表的关联字段没索引的关联查询,一般都会使用 BNL 算法。如果有索引一般选择 NLJ 算法,有 索引的情况下 NLJ 算法比 BNL算法性能更高。

MySQL两个表的亲密接触-连接查询的原理,ORACLE数据库管理-OCP/OCM,mysql,数据库,DBA工程师,OCP,连接查询的原理,数据库管理,oracle

关系型数据库还有一个重要的概念:Join(连接)。使用Join有好处,也会坏处,只有我们明白了其中的原理,才能更多的使用Join。切记不可以:

业务之上,再复杂的查询也在一个连表语句中完成。

敬而远之,DBA每次上报的慢查询都是连接查询导致的,我再也不用了。

连接的本质

我们先来创建两个简单的表,再初始化一些数据

CREATE TABLE t1 (m1 int, n1 varchar(1));

CREATE TABLE t2 (m2 int, n2 varchar(1));

INSERT INTO t1 VALUES(1, 'a'), (2 , 'b') ,(3 ,'c') ;
 
INSERT INTO t2 VALUES(2 , 'b'), (3 , 'c '),(4 , 'd');

从本质上来说,连接就是把各个表的数据都取出来进行匹配,t1 和 t2 的两个表连接起来就是这样的:

MySQL两个表的亲密接触-连接查询的原理,ORACLE数据库管理-OCP/OCM,mysql,数据库,DBA工程师,OCP,连接查询的原理,数据库管理,oracle

连接语法:

select * from t1, t2;

如果乐意,我们可以连接任意数量的表。但是如果不加任何限制条件的话,这个数据量是非常大的,我们现实中使用都是会加上限制条件的。我们来看下下面这条语句

select * from t1,t2 where t1.m1 > 1 and t1.m1 = t2.m2 and t2.n2 = 'c';

这个连接查询的执行过程大致如下

首先确定第一个需要查询 表称为驱动表(t1)

步骤1中从驱动表 (t1) 中每获得一条记录,都要去被驱动表 (t2) 中查询匹配。

从上面的步骤,可以看出上述的连表查询我们需要查询一次t1,两次t2。也就是说,两表的连接查询中,需要查询一次驱动表,被驱动表需要查询多次。

这里需要注意下,并不是将所有满足条件的驱动表记录先查询出来放到一个地方,然后再去被驱动表中查询,(如果满足条件的驱动表中的数据非常多,那要需要多大的内存呀。) 所以是每获得一条驱动表记录就去被驱动表中查询。

内连接和外连接

我们再来创建两个表,并插入一些数据

CREATE TABLE student ( 
number INT NOT NULL Auto_increment comment'学号',
name varchar (5) COMMENT '姓名',
major varchar (30) comment '专业',
PRIMARY KEY (number));

CREATE TABLE score ( 
number INT  comment'学号',
subject varchar (30) COMMENT '科目',
score TINYINT  comment '成绩',
PRIMARY KEY (number, subject));


INSERT INTO `student` (`number`, `name`, `major`) 
VALUES ('20230301', '小赵', '计算机科学');
INSERT INTO `student` (`number`, `name`, `major`) 
VALUES ('20230302', '小钱', '通信');
INSERT INTO `student` (`number`, `name`, `major`) 
VALUES ('20230303', '小孙', '土木工程');

INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230301', '高等数学', '60');
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230301', '英语', '70');
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230302', '高等数学', '80');
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230302', '英语', '90');

如果我们想把所有的学生的成绩都查出来,只需要这样执行:

select s1.number, s1.name, s1.major, s2.subject, s2.score 
  from student as s1 , score as s2 
where s1.number = s2.number;

有个问题就是小孙因为某些原因没有参加考试,所以在结果表中没有对应 的成绩记录。如果老师想查看所有学生的考试成绩,即使是缺考的学生 他们的成绩也应该展示出来。

为了解决这个问题,就有了内连接和外连接的概念:

  • 对于内连接的两个表,若驱动表中的记录在被驱动表找不到匹配的记录,则该记录不会加入到最后的结果集。前面提到的连接都是内连接。

  • 对于外连接的两个表,时驱动表中的记录在被驱动表中没有匹配的记录,也仍然需要加入到结果集。

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

  • 左外连接 选取左侧的表为驱动表。

  • 右外连接·选取右侧的表为驱动表。

当我们使用外连接的时候 有时候我们也不想把驱动表的全部记录都加入到最后的结果集中,这个时候我们就要使用过滤条件了。

• WHERE 子句中的过滤条件:不论是内连接还是外连接 凡是不符合 WHERE 子句中过滤条件的记录都不会被加入到最后的结果集。

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

所以上述的需求我们可以左查询这样来做:

select s1.number, s1.name, s1.major, s2.subject, s2.score 
  from student as s1 left join score as s2 
on s1.number = s2.number;

语法:

#左连接
select * from t1 left join t2 on '连接条件' where '普通过滤条件'
#右连接
select * from t1 right join t2 on '连接条件' where '普通过滤条件'

内连接的另一种写法,也是常用写法

select s1.number, s1.name, s1.major, s2.subject, s2.score 
  from student as s1 inner join score as s2 
where s1.number = s2.number;

语法:

select * from t1 inner join t2 on '连接条件' where '过滤条件'

连接原理

上述说了这么多,知识简单回顾一下连接,左连接,右连接这些概念。接下来我们重点说一下 MySQL 采用了什么样的算法来进行表与表之前的连接。

Nested-Loop Join (嵌套循环连接) NLJ

前面我们已经介绍过了执行连接查询的大致步骤了,我们再来简单回顾一下

  • 步骤1:选取驱动表,使用相关的过滤条件,选取代价最低的单表访问方法来执行访问。

  • 步骤2:对步骤1中查询到的驱动表结果中的每一条记录,都分别在被驱动表中匹配符合条件的记录。

  • 如果有三个表,那么步骤2中得到的结果集就像是新的驱动表,然后第三个表就成为了驱动表,重复上述的过程。

整个过程就像是一个嵌套循环,所以这种连接方式称为 嵌套循环连接 ,这是最简单也是最笨的一种连接查询算法。大致处理过程如下:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions, send to client
    }
  }
}

需要注意的是对于获套循环连接算法法来说,每当我们从驱动表中得到了一条记录时,就根据这条记录立时到被驱动表中查询一次,如果得到了匹配的记录, 就把组合后 的记录发送给客户端,然后再到驱动表中获取下一条记录。这个过程将重复进行。

有什么方式可以优化吗

使用索引加快连接速度

这个是我们比较熟悉的方式,也是相对来说最有用的方式,在被驱动表上创建合适的索引,只返回必要的字段等都可以起到一些优化的作用。

Block Nested-Loop Join(块嵌套循环连接)BNL

每次访问被驱动表,其表中的记录都会被加载到内存中,然后再从驱动表中取出一条与其匹配,匹配结束后清楚内存,然后再从驱动表中加载一条记录,然后把被驱动表的记录加载到内存匹配,如果这个被驱动表中的数据特别多而且不能使用索引进行访问,那就相当于要从磁盘上读这个表好多次,这个IO的代价就非常大了。所以我们得想办法,尽量减少被驱动表的访问次数,于是就出现了下面这种方式。

不再是逐条获取驱动表的数据,而是一块一块的获取,引入join buffer 缓冲区, 将驱动表join 相关的部分数据列(大小受join buffer的限制)缓存到 join buffer中,然后开始扫描被驱动表,被驱动表的每一条记录一次性和join buffer中所有的驱动表记录进行匹配(内存中操作)。将简单嵌套循环中的多次比较合并成一次,降低了备驱动表的访问频率。

这里缓存的不只是关联表的列,select后面的列也会缓存起来。所以查询的时候尽量减少不必要的字段,可以让join buffer中可以存放更多的列。

join_buffer_size的最大值在32为系统中可以申请4G,在64为操作系统中可以申请大于4G的空间。

MySQL两个表的亲密接触-连接查询的原理,ORACLE数据库管理-OCP/OCM,mysql,数据库,DBA工程师,OCP,连接查询的原理,数据库管理,oracle

MySQL对于被驱动表的关联字段没索引的关联查询,一般都会使用 BNL 算法。如果有索引一般选择 NLJ 算法,有 索引的情况下 NLJ 算法比 BNL算法性能更高。

关联查询优化总结

  1. 超过三个表禁止 join。【阿里巴巴JAVA开发手册】

  2. 需要 join 的字段,数据类型必须绝对一致;【阿里巴巴JAVA开发手册】

  3. 多表关联查询时,保证被关联的字段需要有索引,尽量选择NLJ算法。【阿里巴巴JAVA开发手册】

  4. 小表驱动大表,写多表连接sql时如果明确知道哪张表是小表可以用straight_join写法固定连接驱动方式,省去mysql优化器自己判断的时间

MySQL两个表的亲密接触-连接查询的原理,ORACLE数据库管理-OCP/OCM,mysql,数据库,DBA工程师,OCP,连接查询的原理,数据库管理,oracle 文章来源地址https://www.toymoban.com/news/detail-822671.html

到了这里,关于MySQL两个表的亲密接触-连接查询的原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何查询oracle中一个表的一个字段是否加了索引

    要查询Oracle数据库中一个表的一个字段是否已添加索引,可以使用以下SQL语句: 在上面的SQL语句中,将your_table_name替换为你要查询的表的名称,将your_column_name替换为你要查询的字段的名称。 这个查询语句会返回与指定表和字段关联的所有索引的名称和列名称。如果返回结果

    2024年04月16日
    浏览(51)
  • ORACLE:多表连接查询

    目录 一、表连接  二、笛卡尔积(交叉连接) 三、自然连接NATURAL JOIN 四、非等连接 五、外连接 左外连接   右外连接 全外连接  六、自连接 七、多表关联 注:数据来源oracle默认用户Scott中的表 表达式: SELECT table1.column,table2.column FROM table1,table2 WHERE table1.column1=table2.column

    2023年04月13日
    浏览(38)
  • 【MySQL学习】MySQL表的复合查询

    对MySQL表的基本查询还远远达不到实际开发过程中的需求,因此还需要掌握对数据库表的复合查询。本文介绍了多表查询、子查询、自连接、内外连接等复合查询的案例。 来自oracle 9i的经典测试表: emp员工表 dept部门表 salgrade工资等级表 MySQL表的基本查询都是针对一张表进行

    2024年02月03日
    浏览(37)
  • 【MySQL】表的基本查询

    表的增删查改,简称表的 CURD 操作 : Create(创建) , Update(更新) , Retrieve(读取) , Delete(删除). 下面我们逐一进行介绍。 语法: 例如创建一张学生表: (1)单行数据 + 全列插入 接下来我们插入两条记录,其中 value_list 数量必须和定义表的列的数量及顺序一致: 例如插入一

    2024年02月04日
    浏览(50)
  • (完全解决)如何输入一个图的邻接矩阵(每两个点的亲密度矩阵affinity),然后使用sklearn进行谱聚类

    背景 网上倒是有一些关于使用sklearn进行谱聚类的教程,但是这些教程的输入都是一些点的集合,然后根据谱聚类的原理,其会每两个点计算一次亲密度(可以认为两个点距离越大,亲密度越小),假设一共有N个点,那么就是 N*N 个亲密度要计算,这特别像什么?图里面的邻

    2024年02月07日
    浏览(44)
  • Oracle和达梦:连接多行查询结果

    使用LISTAGG函数,您可以将多行数据连接成一个字符串,并指定分隔符进行分隔。这在需要将多行数据合并为单个字符串的情况下非常有用,例如将多个值合并为逗号分隔的列表。 函数介绍 按查询顺序连接 按查询顺序反向连接

    2024年02月08日
    浏览(47)
  • 【MySQL】表的增删改查——MySQL基本查询、数据库表的创建、表的读取、表的更新、表的删除

         CURD是一个数据库技术中的缩写词,它代表Create(创建),Retrieve(读取),Update(更新),Delete(删除)操作。 这四个基本操作是数据库管理的基础,用于处理数据的基本原子操作。      在MySQL中,Create操作是十分重要的,它帮助用于创建数据库对象,如数据

    2024年03月18日
    浏览(69)
  • 8.Oracle中多表连接查询方式

    表连接分类: 内连接、外连接、交叉连接、自连接 1 内连接 内连接是一种常见的多表关联查询方式,一般使用INNER JOIN来实现。其中,INNER可以省略,当只使用JOIN时,语句只表示内连接操作。在使用内连接查询多个表时,必须在FROM子句之后定义一个ON子句

    2024年02月10日
    浏览(39)
  • MySQL--表的基本查询--0410--15

    目录 1. Create 1.1 insert 1.1.2 插入否则更新 1.2 replace 2.Retrieve 2.1 select 2.1.1 全列查询 2.1.2 指定列查询 2.1.3 查询字段为表达式 2.1.4 为查询结果指定名称  2.1.5 去重 2.2 where 2.2.1    and = and and = and = 2.2.2  in  between 2.2.3 查找列数值为null的方法 2.2.4 like  2.2.5 where中使用表达式 2.3 结果

    2024年02月02日
    浏览(42)
  • MySQL:表的约束和基本查询

    表的约束——为了让插入的数据符合预期。 表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primary key,auto_increment,unique key 。 两个值:null(默认的)和not null(不为空) 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因

    2024年02月13日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包