SQL 查询语句执行顺序
SQL 查询语句执行顺序
简述
SQL查询语句的执行顺序与书写顺序不同,具体步骤如下(基于MySQL):
FROM & JOIN
首先确定数据来源,包括表连接操作(如INNER JOIN、LEFT JOIN)。此时会生成一个虚拟表,作为后续步骤的输入 。ON
应用JOIN条件过滤数据,保留满足条件的记录 。WHERE
对虚拟表中的记录进行条件过滤,排除不符合条件的行 。GROUP BY
将数据按指定列分组,为聚合函数(如SUM、COUNT)准备数据 。HAVING
对分组后的结果进行条件过滤(常用于聚合函数的筛选) 。SELECT
选择需要返回的列,计算表达式或别名 。DISTINCT
去除结果集中的重复行(若存在DISTINCT关键字) 。ORDER BY
对最终结果集按指定列排序 。LIMIT
限制返回的行数(如分页或取前N条) 。
关键细节:
ON先于WHERE执行,因此JOIN条件过滤早于WHERE条件 。SELECT中的列别名无法在GROUP BY或HAVING中直接使用,因为它们在执行顺序中更靠后 。- MySQL 8.0已移除查询缓存功能,但执行流程仍遵循上述逻辑 。
示例
SELECT u.*, t.tag_id as t_tag_id, t.tag_name as t_tag_name
FROM user u
LEFT JOIN user_tag ut ON u.user_id = ut.user_id
LEFT JOIN tag t ON ut.tag_id = t.tag_id
AND t.is_deleted = 0
WHERE u.user_id = 6
AND u.is_deleted = 0以下是该SQL语句在数据库中的实际数据流执行过程,结合执行顺序和连接逻辑分析:
- 确定数据源(FROM & JOIN)
主表:从
user u表开始,作为左表。第一次 LEFT JOIN:
将user u与user_tag ut表通过u.user_id = ut.user_id进行左连接。
结果:生成一个虚拟表,包含user表的所有字段,以及user_tag表中匹配的user_id的记录(若无匹配,ut相关字段为NULL)。第二次 LEFT JOIN:
将上一步的虚拟表与tag t表通过ut.tag_id = t.tag_id AND t.is_deleted = 0进行左连接。
关键点:- 连接条件中的
t.is_deleted = 0会过滤tag表中已删除的标签,但保留左表(user和user_tag)的记录。 - 若
user_tag中存在tag_id,但对应的tag表中is_deleted = 1,则t.tag_id和t.tag_name为NULL。
- 连接条件中的
- 应用 WHERE 过滤
- 条件:
u.user_id = 6 AND u.is_deleted = 0- 过滤主表
user中user_id = 6且未被逻辑删除(is_deleted = 0)的记录。 - 注意:此时所有
JOIN已完成,因此WHERE条件仅作用于最终结果集中的user表字段。
- 过滤主表
- 选择输出字段(SELECT)
- 字段:
u.*:返回user表的所有字段。t.tag_id AS t_tag_id和t.tag_name AS t_tag_name:返回tag表中未被删除的标签信息(若无匹配或标签被删除,则为NULL)。
数据流示例
假设以下数据:
user 表:
user_id name is_deleted 6 Alice 0 user_tag 表:
user_id tag_id 6 100 6 101 tag 表:
tag_id tag_name is_deleted 100 VIP 0 101 Admin 1
执行结果:
| user_id | name | is_deleted | t_tag_id | t_tag_name |
|---|---|---|---|---|
| 6 | Alice | 0 | 100 | VIP |
| 6 | Alice | 0 | NULL | NULL |
解释:
- 第一条记录:
tag_id = 100的is_deleted = 0,因此t_tag_id和t_tag_name正常显示。 - 第二条记录:
tag_id = 101的is_deleted = 1,被LEFT JOIN的ON条件过滤,t字段为NULL。 WHERE条件确保仅返回user_id = 6且未被删除的用户。
关键注意事项
LEFT JOIN 的过滤逻辑:
ON条件中的t.is_deleted = 0在连接时生效,直接影响tag表的匹配结果。- 若需保留所有
user_tag记录(包括已删除的标签),需将t.is_deleted = 0移至WHERE子句(但会丢失无匹配标签的用户记录)。
性能优化:
- 在
JOIN前通过WHERE u.user_id = 6提前过滤主表数据,可减少中间表的数据量。 - 确保
user.user_id和tag.tag_id等字段有索引,加速连接操作。
- 在
通过上述步骤,数据库最终返回符合条件的用户及其未被删除的标签信息(若存在)。
[!NOTE]
以上只是逻辑执行过程,实际执行时数据库优化器可能进行优化,比如提前应用 WHERE 条件 以减少中间数据量。

