join 语句使用

目录

前言

创建数据

知识点补充

Join算法Index Nested-Loop

小结:

Join算法Block Nested-Loop

join_buffer放不下驱动表情况

小结:

小表是什么?

总结:

参考内容


前言

在实际开发中,我们一般会有两类问题,为什么我们 DBA 不让使用 join,使用 join 有什么问题呢?如果有两个大小不同的表做 join,应该用哪个表做驱动表呢?MySQL 执行 join 语句的两种可能算法(Index Nested-Loop Join ,Block Nested-Loop Join),这两种算法是由能否使用被驱动表的索引决定的。

创建数据

首先创建表与数据

CREATE TABLE `high`.`testjoin2` 
( `id` INT NOT NULL, 
`index` INT NULL, 
`num` INT NULL, 
PRIMARY KEY ( `id` ), 
INDEX `index` ( `index` ) );

 批量添加数据

PRIMARY KEY ( `id` ), INDEX `index` ( `index` ) );
delimiter ;;
drop procedure idata;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i<=1000)do
    insert into testjoin2 values(i, i, i);
    set i=i+1;
  end while;
end;;
delimiter ;
call idata();

create table testjoin1 like testjoin2;
insert into testjoin1 (select * from testjoin2 where id<=100)

知识点补充

straight_join :目的是MySQL 使用固定的连接方式执行查询。

这里简单说明一下,join语句如果可以用上被驱动表的索引的算法是Index Nested-Loop Join,反之使用的Block Nested-Loop Join算法。

join_buffer 的大小是由参数 join_buffer_size 设定的,默认值是 256k。

Join算法Index Nested-Loop

这里我们知道了可以用上被驱动表的索引的算法是Index Nested-Loop Join,已知创建的表的index有索引所以sql如下:

EXPLAIN select * from  testjoin1 straight_join testjoin2 on (testjoin1.index=testjoin2.index);

 explain 结果:

 从结果可以看出join的过程中使用了testjoin2的index字段索引。

语句执行流程:

  • 从表 testjoin1中读入一行数据A(扫描 100 行);
  • 从该数据A行中,取出 a 字段到表 testjoin2 里去查找(扫描 100 行);
  • 取出表 testjoin2中满足条件的行,跟数据A组成一行,作为结果集的一部分;
  • 重复执行步骤 1 到 3,直到表 testjoin1的末尾循环结束(总共扫描200行)。

这个过程就跟我们写的嵌套查询类似,并且可以用上被驱动表的索引,所以我们称之为“Index Nested-Loop Join。同时这个过程中驱动表是走全表扫描,而被驱动表是走树搜索。每次在被驱动表查一行数据,要先搜索索引 a,再搜索主键索引。

小结:

使用 join 语句,性能比强行拆成多个单表执行 SQL 语句的性能要好;

如果使用 join 语句的话,需要让小表做驱动表。

Join算法Block Nested-Loop

我们知道用不上被驱动表的索引时了mysql选择的Block Nested-Loop Join算法,所以我们将sql改一下:

EXPLAIN select * from testjoin1 straight_join testjoin2 on (testjoin1.index=testjoin2.num);

 explain 结果:

Extra:Using where; Using join buffer (Block Nested Loop) 可以看出使用的Block Nested Loop算法

sql语句执行流程:

  • 把表 testjoin1的数据读入线程内存 join_buffer 中,因为我们这个语句中写的是 select *,所以是把整个表 testjoin1放入了内存;
  • 扫描表 testjoin2,把表 testjoin2中的每一行取出来,跟 join_buffer 中的数据做对比,满足 join 条件的,作为结果集的一部分返回。

从结果可以看出testjoin1扫描了100行,testjoin2扫描了1000行,因为join_buffer 是以无序数组的方式组织的,因此对表 testjoin2中的每一行,都要做 100 次判断(Block Nested-Loop Join 算法的这 10 万次判断是内存操作),总共需要在内存中做的判断次数是:100*1000=10 万次,(扫描行数=testjoin1.rows*testjoin2.rows)。这时候选择大表还是小表做驱动表,扫描行数、执行耗时是样的。

join_buffer放不下驱动表情况

sql语句执行流程:

  • 把表 testjoin1的数据读入线程内存 join_buffer 中时,放了一部分数据放满了,然后紧接着去扫描testjoin2表 testjoin2中的每一行取出来,跟 join_buffer 中的数据做对比,满足条件的数据放入结果集;
  • 把表 testjoin1的剩下的数据分次放入join_buffer,重复以上操作

所以说testjoin1越小或者是join_buffer越大,分的次数就越小,应该让小表当驱动表

小结:

如果在大表上的 join 操作时,可能回扫描被驱动表很多次,会占用大量的系统资源。所以这种 join 尽量不要用。

使用join时,如果join_buffer_size足够大,无论那个表做驱动表结果都一样;如果join_buffer_size不够大时,应该使用小表当驱动表。

小表是什么?

join语法的两个表按照各自的条件过滤,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表。

总结:

如果可以使用被驱动表的索引可以使用join 语句;

如果不能使用被驱动表的索引,然后使用 Block Nested-Loop Join 算法,尽量不要使用join;

在使用 join 的时候,应该让小表做驱动表。

参考内容

如果想知道更多详细内容请自行学习《极客时间mysql实战45讲》34 | 到底可不可以使用join?-极客时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MySQL的JOIN语句用于将两个或多个表中的数据行连接起来,生成一个结果集。JOIN语句的基本语法如下: SELECT 列名1, 列名2, ... FROM 表名1 JOIN 表名2 ON 连接条件 其中,列名是要查询的字段名称,表名是要连接的表名称,连接条件是连接两个表的条件,可以使用“=”、“<”、“>”、“<=”、“>=”等运算符进行比较。 JOIN语句可以使用不同的连接类型,包括INNER JOIN、LEFT JOIN、RIGHT JOIN和FULL OUTER JOIN等。INNER JOIN是最常用的连接类型,它只返回两个表中匹配的行。 例如,如果有两个表A和B,它们有一个共同的字段id,那么可以使用INNER JOIN将它们连接起来: SELECT A.id, A.name, B.address FROM A INNER JOIN B ON A.id = B.id; 这个查询语句将返回表A和表B中id字段相等的行,并且返回A表的name字段和B表的address字段。 除了INNER JOIN之外,还可以使用LEFT JOIN和RIGHT JOIN等连接类型。LEFT JOIN返回左表中所有的行和右表中匹配的行,如果右表中没有匹配的行,则返回NULL值;RIGHT JOIN则返回右表中所有的行和左表中匹配的行,如果左表中没有匹配的行,则返回NULL值。 注意,在使用JOIN语句时,需要确保连接条件正确,否则可能会返回错误的结果。 ### 回答2: MySQL的JOIN语句用于从多个表中检索数据,并根据指定的关联条件将它们连接在一起。JOIN操作可以按需从表中选取相应的字段组合成新的结果集。 JOIN语句的基本语法如下: SELECT 对应字段 FROM 表1 JOIN 表2 ON 条件; JOIN语句中的关键字有INNER JOIN、LEFT JOIN、RIGHT JOIN和FULL OUTER JOIN。这些关键字决定了连接类型。 1. INNER JOIN(内连接):返回两个表中的匹配记录。 语法:SELECT 对应字段 FROM 表1 INNER JOIN 表2 ON 条件; 2. LEFT JOIN(左连接):返回左表中的所有记录以及右表中匹配的记录。 语法:SELECT 对应字段 FROM 表1 LEFT JOIN 表2 ON 条件; 3. RIGHT JOIN(右连接):返回右表中的所有记录以及左表中匹配的记录。 语法:SELECT 对应字段 FROM 表1 RIGHT JOIN 表2 ON 条件; 4. FULL OUTER JOIN(全外连接):返回左右表中的所有记录。 语法:SELECT 对应字段 FROM 表1 FULL OUTER JOIN 表2 ON 条件; 在条件(ON 子句)中,可以使用等于(=)、大于(>)、小于(<)、不等于(<>)等操作符进行比较,还可以使用AND和OR逻辑运算符组合多个条件。 表1和表2之间的连接条件可以是简单的列名比较,也可以是复杂的条件表达式。JOIN语句还可以连接多个表,在FROM子句中通过逗号分隔表名,并按照连接顺序指定JOIN关键字和条件。 JOIN语句使用可以根据具体的需求确定,通过合理使用连接类型和连接条件可以灵活处理各种数据关联需求,实现数据的表之间的联接。 ### 回答3: MySQL中的JOIN语句用于将两个或多个表中的行连接在一起,以便可以根据它们之间的关系检索相关数据。JOIN语句通过共享数据列将表连接在一起,以便在查询结果中能够使用关联的数据。 常见的JOIN类型包括: 1. INNER JOIN:表示只返回两个表中匹配的行,即两个表中连接列的值相等的行。 2. LEFT JOIN:返回左表中的所有行,并包括与右表中匹配的行。如果右表中没有匹配的行,则返回NULL值。 3. RIGHT JOIN:与LEFT JOIN相反,返回右表中的所有行,并包括与左表中匹配的行。如果左表中没有匹配的行,则返回NULL值。 4. FULL OUTER JOIN:返回两个表中的所有行,如果没有匹配的行,则返回NULL值。 JOIN语句的基本语法如下: SELECT 列名 FROM 表1 JOIN 表2 ON 表1.列 = 表2.列; 例如,假设有两个表students和grades,students表包含学生的ID、姓名和年龄,grades表包含学生的ID和考试成绩。要找出每个学生的姓名和考试成绩,可以使用以下SQL查询: SELECT students.姓名, grades.考试成绩 FROM students JOIN grades ON students.ID = grades.ID; 这将返回一个结果集,其中包含每个学生的姓名和对应的考试成绩。 需要注意的是,为了避免数据冗余和提高查询性能,JOIN操作应该尽量避免表之间的重复数据,确保连接列上有正确的索引,并使用适当的JOIN类型来满足查询需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值