在 MySQL 中,SQL 语句的执行顺序并非完全按照书写顺序进行,而是遵循一套逻辑处理流程。以下是 SQL 查询语句的典型执行顺序(以 SELECT 语句为例),帮助理解查询如何被解析和执行:
1. 完整 SQL 语句的书写顺序
SELECT [DISTINCT] <字段列表>
FROM <表名>
[INNER|LEFT|RIGHT JOIN <表名> ON <连接条件>]
WHERE <过滤条件>
GROUP BY <分组字段>
HAVING <分组后过滤条件>
ORDER BY <排序字段>
LIMIT <分页限制>;
2. 实际执行顺序
MySQL 的执行引擎会按以下步骤处理查询(从数据源到结果集):
顺序 | 步骤 | 说明 |
1 | FROM | 确定数据来源,加载表或子查询的数据。 |
2 | ON | 处理 JOIN 的连接条件(筛选符合条件的行)。 |
3 | JOIN | 将关联表的数据合并到主表中(如 LEFT JOIN 保留左表所有行)。 |
4 | WHERE | 对合并后的数据行进行过滤(不可使用 SELECT 中的别名或聚合函数)。 |
5 | GROUP BY | 按指定字段分组(通常伴随聚合函数如 SUM()、COUNT())。 |
6 | HAVING | 对分组后的结果进行过滤(可使用聚合函数和 SELECT 中的别名)。 |
7 | SELECT | 选择最终输出的字段(可定义别名,执行计算或调用函数)。 |
8 | DISTINCT | 去重(若使用了 DISTINCT 关键字)。 |
9 | ORDER BY | 对结果集排序(可使用 SELECT 中的别名)。 |
10 | LIMIT/OFFSET | 限制返回的行数(如分页查询)。 |
3. 关键细节说明
(1) WHERE 与 HAVING 的区别
- WHERE:在分组前过滤数据,不可使用聚合函数(如 SUM())。
- SELECT user_id, COUNT(*) AS cnt FROM orders WHERE amount > 100 -- 先过滤金额大于100的订单 GROUP BY user_id;
- HAVING:在分组后过滤数据,可使用聚合函数。
- SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id HAVING cnt > 5; -- 筛选订单数超过5的用户
(2) 别名的作用域
- SELECT 别名:只能在 HAVING、ORDER BY、LIMIT 中使用,不能在 WHERE 或 GROUP BY 中使用。
- -- 正确示例 SELECT amount * 0.9 AS discount FROM products ORDER BY discount; -- ORDER BY 可使用别名 -- 错误示例 SELECT amount * 0.9 AS discount FROM products WHERE discount > 100; -- WHERE 不能使用别名
(3) 子查询的执行顺序
- FROM 中的子查询:优先执行,生成临时表供主查询使用。
- SELECT * FROM (SELECT id, name FROM users WHERE age > 18) AS adult_users -- 先执行子查询 WHERE name LIKE 'A%';
- WHERE 中的子查询:在 WHERE 阶段执行。
- SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE vip = 1); -- 先执行子查询
4. 示例分析
SELECT
user_id,
COUNT(*) AS order_count
FROM orders
WHERE status = 'completed'
GROUP BY user_id
HAVING order_count > 3
ORDER BY order_count DESC
LIMIT 10;
执行流程:
- FROM orders:加载 orders 表数据。
- WHERE status = 'completed':过滤出状态为“已完成”的订单。
- GROUP BY user_id:按用户分组。
- HAVING order_count > 3:筛选订单数超过3的用户。
- SELECT user_id, COUNT(*) AS order_count:计算每个用户的订单数并命名别名。
- ORDER BY order_count DESC:按订单数降序排序。
- LIMIT 10:返回前10条结果。
5. 性能优化建议
- 优先使用 WHERE 过滤数据:减少 GROUP BY 处理的数据量。
- 为 WHERE 和 JOIN 条件字段建立索引:加速数据过滤和连接。
- 避免在 WHERE 中使用复杂计算或函数:可能导致索引失效。
- 合理使用 EXPLAIN:分析执行计划,优化查询逻辑。
总结:理解 SQL 执行顺序有助于编写高效查询,避免因逻辑错误导致性能问题或结果不符合预期。
可以记 where group having select 这个顺序即可,简化记忆