前言

通常我们写的一个完整的SQL语句都可以拆分成多个子句,子句的执行过程通常会产生虚拟表。什么是虚拟表呢?虚拟表,英文为virtual table,简称为vt。顾名思义,就是实际上并不存在,至少在物理上是不存在的,但是在逻辑上却是存在的表。在MySQL中,有三种虚拟表:临时表、内存表和视图,这里不作详细的介绍,有兴趣的话可以自行查阅资料。回到正题,一条完整的SQL语句在执行的过程中会被拆分为多个SQL子句,每个子句执行时都会产生虚拟表vt,但是最终结果只会返回最后一个虚拟表。从这个思路入手,来理解一下join查询的执行顺序。

join语句的执行顺序

join查询的通用结构如下,SQL如下:

SELECT
	col,
	col2,
	col3...
FROM
	TABLE A LEFT | RIGHT |
	INNER JOIN TABLE B ON < JOIN CONDITION > 
WHERE
	< WHERE CONDITION >;

执行顺序如下:

1、from

SQL语句是从from开始执行的,from是对左右两张表进行笛卡尔积,产生第一张虚拟表vt1.。如果左表中的记录行数是n,右表中的记录行数是m,那么笛卡尔积产生的虚拟表中的记录行数为n * m。

2、on

根据on的条件对vt1表进行筛选,将筛选后的结果保存到虚拟表vt2。

3、join

这一步主要是添加外部行,如果是左连接left join on,那么会先遍历左表中的每一行,然后不在vt2表中的记录将会被插入到vt2,其余字段会置为null,形成虚拟表vt3。如果是右连接right join on,那么会先遍历右表中的每一行,然后不在vt2表中的记录将会插入到vt2,其余字段会置为null。如果是内连接inner join on的话,则不会添加外部行。所产生的vt3表和vt2表是完全相同的。

4、where

对vt3表进行条件过滤,将筛选过滤后的结果保存到表vt4。

5、select

按照查询的字段,从vt4表中取出所需字段,输出到vt5表中,那么最终的返回结果就是vt5表。下面以一个例子来说明join语句的执行顺序。

例子

下面有2张表:a表和b表,a表如下:

preparestatement执行多条语句_字段


a表中一共有9条数据。b表如下:

preparestatement执行多条语句_执行顺序_02


b表中一共有4条数据。现在我想查询id为1006也就是李寻欢的备注是什么,需要用到左连接left join,按照以上的join语句执行顺序来进行:

1、执行from子句

先执行from子句对a表和b表进行笛卡尔积操作,SQL如下:

select * from a
left join b 
on 1;

查询结果如下:

preparestatement执行多条语句_SQL_03


结果过多,这里就不全部展示出来,可以看到,查询结果vt1表中一共有36条数据,也就是9 * 4,刚好是a表和b表数据条数的乘积。

2、执行on过滤并且添加外部行

然后对查询出的结果进行on的筛选过滤,SQL如下:

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

查询结果如下:

preparestatement执行多条语句_执行顺序_04


事实上,加了on条件过滤之后,自动完成了外部行的添加操作,也就是说这一步完成了上面的第2、3步,这个产生的结果为vt3表。

3、执行where过滤

然后对vt3表进行where条件过滤,SQL如下:

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

查询结果如下:

preparestatement执行多条语句_SQL_05


这就是产生的vt4表。

4、select查询所需字段

这里我想获取id,name和content,注意哪个字段来自哪张表,SQL如下:

select a.id,a.name,b.content
from a
left join b 
on a.id = b.id
where a.id = 1006;

查询结果如下:

preparestatement执行多条语句_字段_06


这就是提取所需字段产生的vt5表。最终结果返回的就是vt5虚拟表。

SQL子句的执行顺序不同,产生的查询结果就会不同,因此,在使用join连接查询的时候,弄明白join语句的执行顺序就很有必要,有时使用join连接查询的时候,结果不是我们预期的,这就很可能是顺序的问题,因此,必须要清楚join子句的执行顺序。

一起学习,一起进步,每天只要进步一点点,时间久了,就是质的飞跃。