联接与集合操作

本章介绍联接和集合操作,联接操作主要讲解MySQL数据库支持的三种联接方式,同时也给出了不同ANSI标准的语法。最后对集合操作进行介绍,虽然MySQL数据库只支持UNION集合操作,但用户可以在UNION的基础之上实现EXCEPT和INTERSECT集合操作。

联接查询

联接查询是一种常见的数据库操作,即在两张表(或更多表)中进行行匹配的操作,一般称之为水平操作,这是因为对几张表进行联接操作所产生的结果集可以包含这几张表中所有的列,对应于联接的水平操作,一般将集合操作称为垂直操作。

MySQL数据库支持的联接查询:

  1. CROSS JOIN(交叉联接)
  2. INNER JOIN(内联接)
  3. OUTER JOIN(外联接)
  4. 其他

新旧查询语法

#旧语法
SELECT ...
FROM a,b
WHERE a.x=b.x
#新语法
SELECT ...
FROM a
INNER JOIN b 
ON a.x=b.x

CROSS JOIN

CROSS JOIN对两个表执行笛卡尔积,返回两个表中所有列的组合。


INNER JOIN

在逻辑查询的前三个处理阶段中,INNER JOIN应用前两个阶段,即首先产生笛卡尔积的虚拟表,再按照ON过滤条件来进行数据的匹配操作。INNER JOIN没有第三步操作,即不添加外部行,这是和OUTER JOIN最大的区别之一。正因为不会添加外部行,指定过滤条件在ON子句和WHERE子句中是没有任何区别的。
INNER关键字是可以省略的。
如果INNER JOIN后面不跟ON子句,则相当于CROSS JOIN


OUTER JOIN

与INNER JOIN不同的是,在通过OUTER JOIN添加的保留表中存在未找到的匹配数据。MySQL数据库支持LEFT OUTER JOIN和RIGHT OUTER JOIN,OUTER 可以省略。
OUTER JOIN应用逻辑查询的前三个步骤,即产生笛卡尔积。应用ON过滤器和添加外部行。对于保留表中的行数据,如果是未找到匹配数据而被添加的记录,其值用NULL进行填充。
需要注意的是,INNER JOIN中的过滤条件都可以写在ON子句中,而OUTER JOIN的过滤条件不可以这样处理,因为可能会得到不正确的结果。


NATURAL JOIN

ANSI SQL还支持NATURAL JOIN,即自然联接,NATURAL JOIN等同于INNTER JOIN与USING的组合,它隐含的作用是将两个表中具有相同名称的列进行匹配。同样的,NATURAL LEFT(RIGHT) JOIN 等同于LEFT(RIGHT) OUTER JOIN与USING的组合。


STRAIGHT_JOIN

用户对SQL优化器的控制,等同于JOIN,STRAIGHT_JOIN会强制险读取左边的表。


其他联接分类

SELF JOIN、NONEQUI JOIN和SEMI JOIN
SELF JOIN是同一个表的两个实例之间的JOIN操作。
NONEQUI JOIN的连接条件包含“等于“运算符之外的运算符。
SEMI JOIN是根据一个表中存在的相关记录找到另一个表中相关数据的联接。
ANTI SEMI JOIN根据一个表中不存在的记录而从另一个表中返回记录。


多表联接

多表联接是查询涉及三张或者更多张表之间的联接查询操作。
对于INNER JOIN的多表联接查询,可以随意安排表的顺序,而不会影响查询的结果。


联接算法

联接算法是MySQL数据库用于处理联接的物理策略。目前MySQL数据库仅支持Nested-Loops Join算法。而MariDB还支持Classic Hash Join算法。
当联接的表上有索引时,Nested-Loops Join是非常高效的算法。根据B+树的特性,其联接的时间复杂度为O(N),若没有索引,则可视为最坏的情况,时间复杂度为O( N 2 N^2 )。MySQL数据库根据不同的使用场合,支持两种Nested-Loops Join算法,一种是Simple Nested-Loops Join(NLJ)算法,另一种是Block Nested-Loops Join(BNL)算法。
NLJ从第一张表中每次读取一条记录,然后将记录与嵌套表中的记录进行比较。没有索引时,NLJ会扫描内部表很多次,效率不高。
BNL算法就是针对没有索引的联接情况设计的,其使用Join Buffer来减少内部循环读取表的次数。


到目前为止,一共介绍了两种联接算法:

  1. 加快每次search-for-match(查询比较)操作的速度。
  2. search-for-match根据group(组)来进行,减少对内部表的访问次数。

Batched Key Access Join算法(BKA)

该算法的思想为结合索引和group这两种方法(BNL和NLJ只能使用一个)来提高search-for-match的操作,以此加快联接的执行效率。
该算法只能解决有索引的情况。另一方面,即使有索引,但是当得到的数据占据表中大部分时,直接使用主键索引扫描更有效率。


Classic Hash Join算法

一种广泛应用于数据仓库和OLAP应用的经典联接算法。


集合操作
MySQL数据库支持两种集合操作:UNION ALL和UNION DISTINCT。
集合操作也是对两个输入进行操作,并生成一个虚拟表。
集合操作的两个输入必须拥有两个相同的列数,若数据类型不同,MySQL数据库会自动进行隐式转化。同时,结果列的名称由第一个输入决定。
注意,在集合操作中,INTO OUTFILE只能存在于最后一个SELECT语句中,但导出的结果是整个集合操作的结果。


UNION DISTINCT和UNION ALL

UNION DISTINCT组合两个输入,并应用DISTINCT过滤重复项。一般省略DISTINCT关键字,直接用UNION。
UNION DISTINCT的实现方式如下:

  1. 创建一个临时表,即虚拟表。
  2. 对这张临时表的列添加唯一索引(Unique Index)。
  3. 将输入的数据插入临时表。
  4. 返回虚拟表。

EXCEPT

EXCEPT集合操作允许用户找出位于第一个输入中但不位于第二个输入中的不重复行。同UNION一样,EXCEPT可分为EXCEPT DISTINCT和EXCEPT ALL。
MySQL数据库并不原生支持EXCEPT的语法,不过我们仍然可以通过一些手段来得到EXCEPT的结果。
常见的方法是使用LEFT JOIN或NOT EXISTS,但是直接应用这些方法可能会有一些错误产生。


INTERSECT

INTERSECT返回在两个输入中都出现的行,和EXCEPT一样,不能简单地使用LEFT JOIN或者NOT EXISTS来解决INTERSECT问题,因为同样可能存在NULL值的问题。

猜你喜欢

转载自blog.csdn.net/weixin_41811413/article/details/87866785