前言
通常我们写的一个完整的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表如下:
a表中一共有9条数据。b表如下:
b表中一共有4条数据。现在我想查询id为1006也就是李寻欢的备注是什么,需要用到左连接left join,按照以上的join语句执行顺序来进行:
1、执行from子句
先执行from子句对a表和b表进行笛卡尔积操作,SQL如下:
select * from a
left join b
on 1;
查询结果如下:
结果过多,这里就不全部展示出来,可以看到,查询结果vt1表中一共有36条数据,也就是9 * 4,刚好是a表和b表数据条数的乘积。
2、执行on过滤并且添加外部行
然后对查询出的结果进行on的筛选过滤,SQL如下:
select * from a
left join b
on a.id = b.id;
查询结果如下:
事实上,加了on条件过滤之后,自动完成了外部行的添加操作,也就是说这一步完成了上面的第2、3步,这个产生的结果为vt3表。
3、执行where过滤
然后对vt3表进行where条件过滤,SQL如下:
select * from a
left join b
on a.id = b.id
where a.id = 1006;
查询结果如下:
这就是产生的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;
查询结果如下:
这就是提取所需字段产生的vt5表。最终结果返回的就是vt5虚拟表。
SQL子句的执行顺序不同,产生的查询结果就会不同,因此,在使用join连接查询的时候,弄明白join语句的执行顺序就很有必要,有时使用join连接查询的时候,结果不是我们预期的,这就很可能是顺序的问题,因此,必须要清楚join子句的执行顺序。
一起学习,一起进步,每天只要进步一点点,时间久了,就是质的飞跃。