MySQL--7种join连接

一,定义:

1)LEFT JOIN / LEFT OUTER JOIN:左外连接

左向外连接的结果集包括:LEFT OUTER子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。

2)RIGHT JOIN / RIGHT OUTER JOIN:右外连接

右向外连接是左向外联接的反向连接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。

3)FULL JOIN / FULL OUTER JOIN:全外连接

全外连接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值

二,演示:

1,内连接

SELECT <list> FROM TABLEA A INNER JOIN TABLEB B ON A.key=B.key

2,全外连接 Mysql暂不支持

SELECT <list> FROM TABLEA A FULL OUTER JOIN TABLEB B ON A.key=B.key

3,全外连接-差集 Mysql暂不支持

SELECT <list> FROM TABLEA A FULL OUTER JOIN TABLEB B ON A.key=B.key WHERE A.key IS NULL OR B.key IS NULL

4,左(外)连接

SELECT <list> FROM TABLEA A LEFT JOIN TABLEB B ON A.key=B.key

5,左(外)连接-左表无连接部分

SELECT <list> FROM TABLEA A LEFT JOIN TABLEB B ON A.key=B.key WHERE B.key IS NULL

6,右(外)连接

SELECT <list> FROM TABLEA A RIGHT JOIN TABLEB B ON A.key=B.key

7,右(外)连接-右表无连接部分

SELECT <list> FROM TABLEA A RIGHT JOIN TABLEB B ON A.key=B.key WHERE A.key IS NULL

#内连接
select * from student INNER JOIN shop on student.sid=shop.id;

#全外连接
select * from student FULL OUT JOIN shop on student.sid=shop.id;

#左连接
select * from student LEFT JOIN shop on student.sid=shop.id;

#左外连接
select * from student LEFT JOIN shop on student.sid=shop.id IS NULL;

#右连接
select * from student right JOIN shop on student.sid=shop.id;

#右外连接
select * from student right JOIN shop on student.sid=shop.id is null;

三,外连接消除:

把外连接变为内连接

A OUTER JOIN B

变形为

A JOIN B

外连接消除的意义:

1 查询优化器在处理外连接操作时所需执行的操作和时间多于内连接

2 外连接消除后,优化器在选择多表连接顺序时,可以有更多更灵活的选择,从而可以选择更好的表连接顺序,加快查询执行的速度

3 表的一些连接算法(如块嵌套连接和索引循环连接等)在将规模小的或筛选条件最严格的表作为“外表”(放在连接顺序的最前面,是多层循环体的外循环层),可以减少不必要的I/O开销,能加快算法执行的速度

外连接消除的条件:

WHERE子句中的条件满足“空值拒绝” (又称为“reject-NULL”条件)。

WHERE条件 可以保证 从结果中 排除外连接右侧(右表)生成的值为NULL的行(即条件确保应用在右表带有空值的列对象上时,条件不满足,条件的结果值为FLASE或UNKONOWEN,这样右表就不会有值为NULL的行生成),所以能使该查询在语义上等效于内连接。

explain

SELECT * FROM X LEFT JOIN Y ON (X.X_num=Y.Y_num)

WHERE Y.Y_num IS NOT NULL;

Mysql优化器对外连接的优化处理:

例1

explain extended select * from a left join b on a.id=b.uid where a.id=b.uid;

优化后:

select `test`.`a`.`id` AS `id`,`test`.`a`.`name` AS `name`,`test`.`a`.`age` AS `age`,`test`.`b`.`uid` AS `uid`,`test`.`b`.`score` AS `score`,`test`.`b`.`class` AS `class` from `test`.`a` join `test`.`b` where (`test`.`b`.`uid` = `test`.`a`.`id`)

例2

explain extended select * from a left join b on a.id=b.uid where b.uid is not null;

优化后:

select `test`.`a`.`id` AS `id`,`test`.`a`.`name` AS `name`,`test`.`a`.`age` AS `age`,`test`.`b`.`uid` AS `uid`,`test`.`b`.`score` AS `score`,`test`.`b`.`class` AS `class` from `test`.`a` join `test`.`b` where ((`test`.`b`.`uid` = `test`.`a`.`id`) and (`test`.`a`.`id` is not null))

例3

select * from a left join b on a.id=b.uid;

select * from a left outer join b on a.id=b.uid where a.id=b.uid;

select * from a left join b on true where a.id=b.uid;

这2名sql,Mysql处理后,都优化成内连接

select `test`.`a`.`id` AS `id`,`test`.`a`.`name` AS `name`,`test`.`a`.`age` AS `age`,`test`.`b`.`uid` AS `uid`,`test`.`b`.`score` AS `score`,`test`.`b`.`class` AS `class` from `test`.`a` join `test`.`b` where (`test`.`b`.`uid` = `test`.`a`.`id`)

外连接消除示例1:---辨析ON和WHERE的差异

ON t_1_id = t_2_id:

t_1_id 和 t_2_id 进行连接

WHERE t_1_id = t_2_id:

当t_1_id 和 t_2_id的值相等

外连接消除示例2:---深入理解WHERE条件对外连接优化的影响

外表的索引列出现在WHERE子句中:

EXPLAIN EXTENDED SELECT * FROM t_1 LEFT JOIN t_2 ON t_1_id = t_2_id WHERE t_1_id>0;

优化后

select `tt2`.`t_1`.`t_1_id` AS `t_1_id`,

`tt2`.`t_1`.`t_1_col_1` AS `t_1_col_1`,

`tt2`.`t_1`.`t_1_col_2` AS `t_1_col_2`,`tt2`.`t_2`.`t_2_id` AS `t_2_id`,

`tt2`.`t_2`.`t_2_col_1` AS `t_2_col_1`,`tt2`.`t_2`.`t_2_col_2` AS `t_2_col_2`

from `tt2`.`t_1` left join `tt2`.`t_2`on((`tt2`.`t_2`.`t_2_id` = `tt2`.`t_1`.`t_1_id`))

where (`tt2`.`t_1`.`t_1_id` > 0)

内表的索引列出现在WHERE子句中:

EXPLAIN EXTENDED SELECT * FROM t_1 LEFT JOIN t_2 ON t_1_id = t_2_id WHERE t_2_id>0;

优化后

select `tt2`.`t_1`.`t_1_id` AS `t_1_id`,

`tt2`.`t_1`.`t_1_col_1` AS `t_1_col_1`,`tt2`.

`t_1`.`t_1_col_2` AS `t_1_col_2`,`tt2`.`t_2`.`t_2_id` AS `t_2_id`,

`tt2`.`t_2`.`t_2_col_1` AS `t_2_col_1`,`tt2`.`t_2`.`t_2_col_2` AS `t_2_col_2`

from `tt2`.`t_1` join `tt2`.`t_2`

where ((`tt2`.`t_2`.`t_2_id` = `tt2`.`t_1`.`t_1_id`) and

(`tt2`.`t_1`.`t_1_id` > 0))

外连接消除总结:

1 注意外连接与内连接的语义差别

2 外连接优化的条件:空值拒绝

3 外连接优化的本质:语义上是外连接,但WHER条件 使得 外连接可以蜕化为内连接

四,连接消除:

去掉不必要的连接对象,则减少了连接操作

连接消除的条件:

无固定模式,具体问题具体处理

连接消除情况一:

唯一键/主键作为连接条件,三表内连接可以去掉中间表

(中间表的列只作为连接条件)

CREATE TABLE A (a1 INT UNIQUE, a2 VARCHAR(9), a3 INT);

CREATE TABLE B (b1 INT UNIQUE, b2 VARCHAR(9), c2 INT);

CREATE TABLE C (c1 INT UNIQUE, c2 VARCHAR(9), c3 INT);

B的列在WHERE条件子句中只作为等值连接条件存在,则查询可以去掉对B的连接操作:

SELECT A.*, C.* FROM A JOIN B ON (a1=b1) JOIN CON (b1=c1);

相当于:

SELECT A.*, C.* FROM A JOIN C ON (a1= c1);

连接消除情况二:

一些特殊形式,可以消除连接操作(可消除的表除了作为连接对象外,不出现在任何子句中)。

示例:

SELECT MAX(a1) FROM A, B;/* 在这样格式中的MIN、MAX函数操作可以消除连接,去掉B表不影响结果;其他聚集函数不可以 */

SELECT DISTINCT a3 FROM A, B; /* 对连接结果中的a3列执行去重操作*/

SELECT a1 FROM A, B GROUP BY a1;/* 对连接结果中的a1列执行分组操作 */

连接消除情况三:

主外键关系的表进行的连接,可消除主键表,这不会影响对外键表的查询。

连接消除示例:---创建对象

创建表,命令如下:

CREATE TABLE B (b1 INT, b2 VARCHAR(2), PRIMARY KEY(b1));

CREATE TABLE A (a1 INT, a2 VARCHAR(2), FOREIGN KEY(a1) REFERENCES B(b1) );/* A作为外键表参照主键表B */

CREATE TABLE C (c1 INT, c2 VARCHAR(2));

插入数据,命令如下:

INSERT INTO B VALUES(1, ‘B1‘);

INSERT INTO B VALUES(2, ‘B2‘);

INSERT INTO B VALUES(3, ‘B3‘);

INSERT INTO A VALUES(1, ‘A1‘);

INSERT INTO A VALUES(null, ‘A2‘);

INSERT INTO A VALUES(3, ‘A3‘);

INSERT INTO C VALUES(1, ‘C1‘);

INSERT INTO C VALUES(2, ‘C2‘);

INSERT INTO C VALUES(NULL, ‘C3‘);

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第一条SQL:

三个表做内连接,但目标列不包括主键表B的对象,主键表B只作为连接对象和连接条件存在;

mysql> SELECT A.*, C.* FROM A,B,C WHERE A.a1=B.b1 AND B.b1=C.c1; //主键表B作为连接对象和连接条件存在

+------+------+------+------+

| a1 | a2 | c1 | c2 |

+------+------+------+------+

| 1 | A1 | 1 | C1 |

+------+------+------+------+

1 row in set (0.05 sec)

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第一条SQL:

三个表做内连接,但目标列不包括主键表B的对象,主键表B只作为连接对象和连接条件存在;

mysql> EXPLAIN EXTENDED SELECT A.*, C.* FROM A,B,C WHERE A.a1=B.b1 AND B.b1=C.c1;

+----+-------------+-------+--------+---------------+---------+---------+------+

| id | select_type | table | type | possible_keys | key | key_len | ref |

+----+-------------+-------+--------+---------------+---------+---------+------+

| 1 | SIMPLE | C | ALL | NULL | NULL | NULL | NULL |

| 1 | SIMPLE | B | eq_ref | PRIMARY | PRIMARY | 4 | test.C.c1|

| 1 | SIMPLE | A | ALL | a1 | NULL | NULL | NULL |

+----+-------------+-------+--------+---------------+---------+---------+------+

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第一条SQL:

三个表做内连接,但目标列不包括主键表B的对象,主键表B只作为连接对象和连接条件存在;

被查询优化器处理后的语句为:

/* select#1 */ select `test`.`a`.`a1` AS `a1`, `test`.`a`.`a2` AS `a2`,

` test`.`c`.`c1` AS `c1`, `test`.`c`.`c2` AS `c2`

from `test`.`a` join `test`.`b` join `test`.`c`

where ((`test`.`b`.`b1` = `test`.`c`.`c1`) and (`test`.`a`.`a1` = `test`.`c`.`c1`))

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第二条SQL:

只有表A和表C进行连接,但WHERE子句多一条判定条件“A.a1 IS NOT NULL”;

mysql> SELECT A.*, C.* FROM A,C WHERE A.a1=C.c1 AND A.a1 IS NOT NULL; //只有表A和C进行连接

+------+------+------+------+

| a1 | a2 | c1 | c2 |

+------+------+------+------+

| 1 | A1 | 1 | C1 |

+------+------+------+------+

1 row in set (0.01 sec)

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第二条SQL:

只有表A和表C进行连接,但WHERE子句多一条判定条件“A.a1 IS NOT NULL”;

查询执行计划如下:

mysql> EXPLAIN EXTENDED SELECT A.*, C.* FROM A,C WHERE A.a1=C.c1 AND A.a1 IS NOT NULL;

+----+-------------+-------+------+---------------+------+---------+-----------+

| id | select_type | table | type | possible_keys | key | key_len | ref |

+----+-------------+-------+------+---------------+------+---------+-----------+

| 1 | SIMPLE | C | ALL | NULL | NULL | NULL | NULL |

| 1 | SIMPLE | A | ref | a1 | a1 | 5 | test.C.c1 |

+----+-------------+-------+------+---------------+------+---------+-----------+

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第二条SQL:

只有表A和表C进行连接,但WHERE子句多一条判定条件“A.a1 IS NOT NULL”;

被查询优化器处理后的语句为:

/* select#1 */ select `test`.`a`.`a1` AS `a1`, `test`.`a`.`a2` AS `a2`,

`test`.`c`.`c1` AS `c1`, `test`.`c`.`c2` AS `c2`

from `test`.`a` join `test`.`c`

where ((`test`.`a`.`a1` = `test`.`c`.`c1`) and (`test`.`c`.`c1` is not null))

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第三条SQL:

只有表A和表C进行连接,但WHERE子句比第二条SQL的WHERE子句内容更为简单

mysql> SELECT A.*, C.* FROM A,C WHERE A.a1=C.c1;

+------+------+------+------+

| a1 | a2 | c1 | c2 |

+------+------+------+------+

| 1 | A1 | 1 | C1 |

+------+------+------+------+

1 row in set (0.00 sec)

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表

MySQL不支持

第三条SQL:

只有表A和表C进行连接,但WHERE子句比第二条SQL的WHERE子句内容更为简单

mysql> EXPLAIN EXTENDED SELECT A.*, C.* FROM A,C WHERE A.a1=C.c1;

+----+-------------+-------+------+---------------+------+---------+------+

| id | select_type | table | type | possible_keys | key | key_len | ref |

+----+-------------+-------+------+---------------+------+---------+------+

| 1 | SIMPLE | C | ALL | NULL | NULL | NULL | NULL |

| 1 | SIMPLE | A | ALL | a1 | NULL | NULL | NULL |

+----+-------------+-------+------+---------------+------+---------+------+

连接消除示例1:---对主外键参照的表进行内连接,可以消除主键表 MySQL不支持

第一条SQL:

EXPLAIN EXTENDED SELECT A.*, C.* FROM A,B,C WHERE A.a1=B.b1 AND B.b1=C.c1;

第二条SQL:

EXPLAIN EXTENDED SELECT A.*, C.* FROM A,C WHERE A.a1=C.c1 AND A.a1 IS NOT NULL;

第三条SQL:

EXPLAIN EXTENDED SELECT A.*, C.* FROM A,C WHERE A.a1=C.c1;

连接消除示例2:---对主外键参照的表进行外连接,可以消除主键表 MySQL不支持

表A外连接表B,然后连接表C,查询目标列没有表B的列,表B没有被消除,查询执行计划如下:

mysql> EXPLAIN EXTENDED SELECT A.*, C.* FROM A LEFT JOIN B ON (a1=b1) JOIN C ON (a1=c1);

+----+-------------+-------+--------+---------------+-----------------------------------------------

| id | select_type | table | type | possible_keys | Extra |

+----+-------------+-------+--------+---------------+-----------------------------------------------

| 1 | SIMPLE | C | ALL | NULL | NULL

| 1 | SIMPLE | A | ALL | a1 | Using where; Using join buffer (Block Nested L

| 1 | SIMPLE | B | eq_ref | PRIMARY | Using index

+----+-------------+-------+--------+---------------+-----------------------------------------------

连接消除示例2:---对主外键参照的表进行外连接,可以消除主键表 MySQL不支持

被查询优化器处理后的语句为:

/* select#1 */ select `test`.`a`.`a1` AS `a1`, `test`.`a`.`a2` AS `a2`,

`test`.`c`.`c1` AS `c1`, `test`.`c`.`c2` AS `c2`

from `test`.`a` left join `test`.`b` on((`test`.`b`.`b1` = `test`.`c`.`c1`)) join `test`.`c`

where (`test`.`a`.`a1` = `test`.`c`.`c1`)

连接消除总结:

注意连接消除与外连接消除的技术差别

连接消除去掉的是被连接的某个对象

外连接消除去掉的是外连接的语义,变形为内连接

五,嵌套连接消除:

连接存在多个层次,用括号标识连接的优先次序。

嵌套连接消除,就是消除嵌套的连接层次,把多个层次的连接减少为较少层次的连接,尽量“扁平化”

嵌套连接消除示例:

创建表,命令如下:

CREATE TABLE B (b1 INT, b2 VARCHAR(9));

CREATE TABLE A (a1 INT, a2 VARCHAR(9));

CREATE TABLE C (c1 INT, c2 VARCHAR(9));

插入数据,命令如下:

INSERT INTO B VALUES(1, ‘B1‘), (NULL, ‘B2‘), (31, ‘B31‘), (32, ‘B32‘), (NULL, ‘B4‘),(5, ‘B5‘), (6, ‘B6‘);

INSERT INTO A VALUES(1, ‘A1‘), (null, ‘A2‘), (NULL, ‘A31‘), (32, ‘A32‘), (4, ‘A4‘), (5, ‘A5‘), (NULL, ‘A6‘);

INSERT INTO C VALUES(1, ‘C1‘), (NULL, ‘C2‘), (31, ‘C31‘), (NULL, ‘C32‘), (4, ‘C4‘), (NULL, ‘C5‘),(6, ‘A6‘);

嵌套连接消除示例1:

SQL语句的语义是B和C先连接,然后再和A连接。查询执行计划如下:

mysql> EXPLAIN EXTENDED SELECT * FROM A JOIN (B JOIN C ON B.b1=C.c1) ON A.a1=B.b1

WHERE A.a1 > 1;

+----+-------------+-------+------------+------+------+----------+--------------------------------------------

| id | select_type | table | partitions | type | rows | filtered | Extra

+----+-------------+-------+------------+------+------+----------+--------------------------------------------

| 1 | SIMPLE | A | NULL | ALL | 7 | 33.33 | Using where |

| 1 | SIMPLE | B | NULL | ALL | 7 | 14.29 | Using where; Using join buffer (Block Nested Loop) |

| 1 | SIMPLE | C | NULL | ALL | 7 | 14.29 | Using where; Using join buffer (Block Nested Loop) |

+----+-------------+-------+------------+------+------+----------+--------------------------------------------

3 rows in set, 2 warnings (0.02 sec)

嵌套连接消除示例1:

被查询优化器处理后的语句为:

/* select#1 */ select `test`.`a`.`a1` AS `a1`,`test`.`a`.`a2` AS `a2`,

`test`.`b`.`b1` AS `b1`,`test`.`b`.`b2` AS `b2`,`test`.`c`.`c

1` AS `c1`,`test`.`c`.`c2` AS `c2`

from `test`.`a` join `test`.`b` join `test`.`c`

where ((`test`.`b`.`b1` = `test`.`a`.`a1`) and

(`test`.`c`.`c1` = `test`.`a`.`a1`) and (`test`.`a`.`a1` > 1))

嵌套连接消除总结:

1 嵌套连接消除的连接的层次,这是一种连接的语义顺序的变化

2 连接消除,消掉的是一些被连接的对象

3 外连接消除,消掉的是外连接的语义,使得外连接变形为内连接

原文:https://blog.csdn.net/flyfreelyit/article/details/80136459
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/serendipme/p/10792016.html

时间: 2024-11-13 10:04:21

MySQL--7种join连接的相关文章

Mysql七种 JOIN 连接

内连接 SELECT <select_list> FROM TableA A INNER JOIN TableB B ON A.Key = B.Key 左外连接 SELECT <select_list> FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key SELECT <select_list> FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key WHERE B.Key IS

数据库(学习整理)----7--Oracle多表查询,三种join连接

聚合函数:(都会忽略null数据) 常用的有5种:将字段中所有的数据聚合在一条中 1.sum(字段名) :求总和 2.avg(字段名) :求平均值 3.max(字段名) :求最大值 4.min(字段名) :求最小值 5.count(字段名.*) :统计行数 ----2.按部门编号,查询平均薪水 ,并且平均薪水<1300的不显示,结果按降序排序 select empno,avg(sal) as avgsal from scott.emp group by empno having avg(sal)

mysql 7 种 join

一. select * from A inner join B on A.key = B.key 二. select * from A left join B on A.key = B.key 三. select * from A right join B on A.key = B.key 四. select * from A left join B on A.key = B.key where b.key is null 五. select * from A right join B on A

两种方法连接MySql数据库

1.用MySQLDriverCS连接MySQL数据库 先下载和安装MySQLDriverCS,在安装文件夹下面找到MySQLDriver.dll,然后将MySQLDriver.dll添加引用到项目中. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Odbc; using System.Drawing; using S

Python/MySQL表操作以及连接

Python/MySQL表操作以及连接 mysql表操作: 主键:一个表只能有一个主键.主键可以由多列组成. mysql> create table yuan(id int auto_increment,yuangongname int,bumen_id int, primary key(id,yuangongname))engine=innodb default charset=utf8; Query OK, 0 rows affected (0.43 sec) 外键 :可以进行联合外键,操作

MySQL 几种调式分析利器

原文:MySQL 几种调式分析利器 目录 pstack gdb strace perf pstack 获取堆栈信息 问题线程的定位 负载较低 mysql_pid=4522 pstack $mysql_pid>pstack.info pt-pmp对堆栈信息排序 pt-pmp pstack.info | less 也可以直接执行pt-pmp pt-pmp --pid 4522 如 10 __io_getevents_0_4(libaio.so.1),LinuxAIOHandler::collect(

【知识库】-数据库_MySQL 的七种 join

作者:haifeisi 文章出处: MySQL 的七种 join 创建数据库表'tbl_dept'和'tbl_emp' CREATE DATABASE db0206; USE db0206; CREATE TABLE `db0206`.`tbl_dept`( `id` INT(11) NOT NULL AUTO_INCREMENT, `deptName` VARCHAR(30), `locAdd` VARCHAR(40), PRIMARY KEY (`id`) ) ENGINE=INNODB C

SQL Server三种表连接原理

http://msdn.microsoft.com/zh-cn/library/dn144699.aspx 简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge Join,Hash Join这三种物理连接中的一种.理解这三种物理连接是理解在表连接时解决性能问题的基础,下面我来对这三种连接的原理,适用场景进行描述. 嵌套循环连接(Nested Loop J

JS中三种字符串连接方式及其性能比较

工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方法,这里将它们一一列出顺便也对它们的性能做个具体的比较. 第一种方法  用连接符“+”把要连接的字符串连起来: str="a"; str+="b"; 毫无疑问,这种方法是最便捷快速的,如果只连接100个以下的字符串建议用这种方法最方便. 第二种方法  以数组作为中介用 join 连接字符串: var arr=new Array(); arr.push(a); arr.push