作者:唐叔在学习
专栏:数据库学习
SEO关键词:SQL执行顺序、SELECT语句、SQL优化、大数据开发、数据分析、LeetCode SQL、MySQL、SQL面试题、GROUP BY、HAVING、JOIN、WHERE、ORDER BY、LIMIT、分页查询、SQL调优
大家好,我是你们的老朋友唐叔!今天我们来聊聊SQL中最核心的SELECT语句的执行顺序问题。这个问题在程序员面试中出现的频率极高,也是很多新手容易搞混的知识点。掌握它不仅能让你的SQL查询更高效,还能在面试中脱颖而出!
文章目录
一、为什么需要了解SELECT执行顺序?
很多同学写SQL时,只是机械地按照SELECT-FROM-WHERE这样的顺序写,却不了解数据库引擎实际执行的顺序。这就好比你知道汽车的油门、刹车和方向盘在哪,但不知道它们的工作原理,遇到复杂路况就容易出问题。
面试高频考点:90%的SQL面试都会问到执行顺序问题,特别是大数据开发、数据分析师等岗位。
二、SELECT语句的"表面顺序"和"真实顺序"
1. 我们写的顺序(表面顺序)
SELECT [DISTINCT] 列名
FROM 表名
[JOIN 表名 ON 连接条件]
[WHERE 条件]
[GROUP BY 分组列]
[HAVING 分组后条件]
[ORDER BY 排序列]
[LIMIT 行数]
2. 数据库执行的顺序(真实顺序)
这才是重点!数据库引擎实际是这样处理的:
- FROM:先确定数据来源(查哪张表)
- JOIN:如果有表连接,此时执行
- WHERE:对原始数据进行过滤
- GROUP BY:对过滤后的数据分组
- HAVING:对分组后的结果再过滤
- SELECT:选择要显示的列
- DISTINCT:去重
- ORDER BY:排序
- LIMIT:限制返回行数
唐叔口诀:弗(FROM)建(JOIN)委(WHERE)组(GROUP BY)会(HAVING)选(SELECT)帝(DISTINCT)欧(ORDER BY)李(LIMIT)
三、各关键字详解与避坑指南
1. FROM - 数据来源
语法:FROM table1 [AS alias1]
注意事项:
- 多表查询时,小表放前面性能更好(SQL优化技巧)
- 表别名可以提高可读性
2. JOIN - 表连接(大数据开发重点)
类型:
- INNER JOIN(内连接)
- LEFT JOIN(左连接)
- RIGHT JOIN(右连接)
- FULL JOIN(全连接)
- CROSS JOIN(笛卡尔积)
避坑:
-- 错误写法(ON条件放WHERE后面)
SELECT * FROM A JOIN B WHERE A.id=B.id
-- 正确写法
SELECT * FROM A JOIN B ON A.id=B.id
3. WHERE - 行级过滤
常见错误:在WHERE中使用SELECT中定义的别名(此时别名还不存在!)
-- 错误示例
SELECT salary*12 AS annual_salary
FROM employees
WHERE annual_salary > 100000 -- 报错!
-- 正确写法
SELECT salary*12 AS annual_salary
FROM employees
WHERE salary*12 > 100000
4. GROUP BY - 分组统计(数据分析核心)
语法:GROUP BY column1 [, column2...]
黄金法则:SELECT中的非聚合列必须出现在GROUP BY中
-- 错误示例
SELECT Name, Description, COUNT(Name)
FROM Product
GROUP BY Name -- Description不在GROUP BY中
-- 正确写法
SELECT Name, Description, COUNT(Name)
FROM Product
GROUP BY Name, Description
常见的聚合列有:
函数 | 说明 | 示例 |
---|---|---|
COUNT() | 计数 | COUNT(*) 计算行数 |
SUM() | 求和 | SUM(salary) 计算总和 |
AVG() | 平均值 | AVG(score) 计算平均分 |
MAX() | 最大值 | MAX(price) 找出最贵价格 |
MIN() | 最小值 | MIN(age) 找出最小年龄 |
5. HAVING - 分组后过滤
与WHERE的区别:
- WHERE过滤原始数据
- HAVING过滤分组后的数据
-- 查询平均工资>50000的部门
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000
6. SELECT - 选择列
性能提示:
- 避免使用SELECT *,只查询需要的列
- 计算列会消耗性能
7. ORDER BY - 排序
语法:ORDER BY column1 [ASC|DESC] [, column2...]
注意:
- 排序是性能杀手,大数据量时要谨慎
- 可以按SELECT中的别名排序
8. LIMIT - 限制行数(分页查询必备)
分页公式:LIMIT (page_num-1)*page_size, page_size
四、实战案例分析(LeetCode高频题型)
案例1:查询各部门薪资最高的员工
原题:https://leetcode.cn/problems/department-highest-salary/description/
SELECT e.department, e.employee_name, e.salary
FROM employees e
WHERE (e.department, e.salary) IN (
SELECT department, MAX(salary)
FROM employees
GROUP BY department
)
ORDER BY e.salary DESC;
执行顺序分析:
- 先执行子查询中的FROM-GROUP BY-SELECT
- 然后执行主查询的FROM-WHERE-SELECT-ORDER BY
案例2:LeetCode第176题 - 第二高的薪水
原题:https://leetcode.cn/problems/second-highest-salary/description/
SELECT (
SELECT DISTINCT salary
FROM employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1
) AS SecondHighestSalary;
五、性能优化建议(SQL调优关键)
-
WHERE条件中避免使用函数,会导致索引失效
-- 不好 WHERE YEAR(create_time) = 2023 -- 好 WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'
-
多表JOIN时,小表驱动大表
-
GROUP BY字段加上索引
六、常见面试题
- WHERE和HAVING的区别是什么?
- GROUP BY和ORDER BY可以一起用吗?
- LIMIT可以在子查询中使用吗?
- 如何优化一个执行很慢的SELECT查询?
(答案都在文中哦~)
总结
记住唐叔的口诀:弗建委会选帝欧李(FROM-JOIN-WHERE-GROUP BY-HAVING-SELECT-DISTINCT-ORDER BY-LIMIT),SELECT语句的执行顺序就再也不会搞混了!
觉得有用的话,别忘了点赞收藏!
往期数据库文章推荐