学到这里,我们已经写了无数个 SQL 查询了,但是还是很难确切的说出它的执行顺序。
下面看看 SELECT 语句的完整语法,如下:
SELECT
DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>
其执行顺序如下:
FROM
<表名> # 笛卡尔积
ON
<筛选条件> # 对笛卡尔积的虚表进行筛选
JOIN <JOIN,LEFT JOIN,RIGHT JOIN...>
<JOIN表> # 指定JOIN,用于添加数据到ON之后的虚表中,例如LEFT JOIN会将左表的剩余数据添加到虚表中
WHERE
<WHERE条件> # 对上述虚表进行筛选
GROUP BY
<分组条件> # 分组
<SUM()等聚合函数> # 用于HAVING子句进行判断,在书写上这类聚合函数是写在HAVING判断里面的
HAVING
<分组筛选> # 对分组后的结果进行聚合筛选
SELECT
<返回数据列表> # 返回的单列必须在GROUP BY子句中,聚合函数除外
DISTINCT
# 数据除重
ORDER BY
<排序条件> # 排序
LIMIT
<行数限制>
引擎在执行上述每一步时,都会在内存中形成一张虚拟表,然后对虚拟表进行后续操作,并释放没用的虚拟表的内存,以此类推。
下面我们具体介绍一下 SQL 查询语句的执行顺序(下面“VT”表示虚拟表)
需要注意的是:
根据以上内容,我们可以回答以下经常遇到的问题:
但是在实际应用中,数据库不一定会按照 JOIN、WHERE、GROUP BY 的顺序来执行查询。因为它们会进行一系列优化,在不改变查询结果的前提下,把执行顺序打乱,从而让查询执行得更快。
比如:
SELECT * FROM score sc LEFT JOIN student stu ON sc.student_id = stu.id WHERE s.name = '城东书院'
以上语句只需要找出名字叫“城东书院”的学生信息,那就没必要对两张表的所有数据执行左连接。在连接之前系统先进行过滤,这样查询会快得多,而且对于这个查询来说,先执行过滤并不会改变查询结果。