子查询是SQL中嵌套在主查询内的SELECT语句,用于提供过滤条件、计算结果或临时数据集。它可在WHERE、FROM、SELECT、HAVING和EXISTS子句中使用,常见于查找高于平均值的记录、构建派生表、返回标量值或判断存在性。例如,通过WHERE子查询筛选订单金额高于平均值的客户;在FROM子句中创建部门平均工资的临时表;用SELECT子句添加部门平均工资字段;利用EXISTS判断客户是否有订单。但子查询可能引发性能问题,尤其是关联子查询会逐行执行,导致效率低下。优化方法包括:将关联子查询重写为JOIN,以减少执行次数;用EXISTS替代IN避免大结果集加载;为子查询字段建立索引;并通过EXPLAIN分析执行计划。选择子查询还是JOIN需权衡可读性与性能:子查询逻辑清晰适合简单条件或标量值获取,JOIN则在多表关联、大数据量和高性能需求时更优。实践中应先确保逻辑正确,再根据数据规模和性能表现进行优化。

SQL中的子查询,简单来说,就是在一个SQL查询语句内部,再嵌入另一个完整的SELECT语句。它就像是主查询的一个“辅助部队”,用来提供数据、过滤条件或者计算结果,让主查询能够完成更复杂的任务。在我看来,子查询是SQL强大灵活性的一个重要体现,它能让原本可能需要多步操作才能完成的逻辑,在一句话里搞定。
子查询(Subquery),也常被称为内部查询(Inner Query)或嵌套查询(Nested Query),顾名思义,它是一个被包含在其他SQL语句(如SELECT, INSERT, UPDATE, DELETE)中的查询。这个内部查询会先执行,然后将其结果作为外部查询(Outer Query)的输入或条件。
我个人觉得,子查询的存在,很大程度上是为了解决那些“依赖于某个未知结果”才能进行下一步判断的问题。比如,我想找出那些销售额高于平均销售额的产品,或者我想知道哪些员工的工资比他们部门的平均工资还高。这些问题,如果没有子查询,你可能得先查出平均值,再用这个平均值去做第二次查询,显得有点笨拙。
子查询的应用场景非常广泛,常见于:
WHERE column IN (SELECT ...)
WHERE column > (SELECT MAX(...))
说到嵌套查询的写法,其实花样不少,但核心思路都是把子查询的结果作为主查询的一部分。这里我列举几个我在实际工作中经常会用到的模式,并分享一些我的心得。
1. WHERE子句中的子查询:最直观的过滤
-- 找出所有订单金额高于平均订单金额的客户 SELECT customer_id, customer_name FROM Customers WHERE customer_id IN (SELECT customer_id FROM Orders WHERE total_amount > (SELECT AVG(total_amount) FROM Orders));
这个例子里,我用了两个嵌套。内层子查询计算平均订单金额,外层子查询找出高于这个平均金额的订单的客户ID。最后,主查询根据这些客户ID来筛选。这种写法非常直观,读起来也容易理解,但要注意,如果子查询返回的结果集太大,
IN
2. FROM子句中的子查询:构建临时“视图”
-- 计算每个部门的平均工资,并找出高于公司整体平均工资的部门
SELECT department_name, avg_salary
FROM (
SELECT d.department_name, AVG(e.salary) AS avg_salary
FROM Employees e
JOIN Departments d ON e.department_id = d.department_id
GROUP BY d.department_name
) AS DepartmentAvgSalary -- 注意:FROM子句中的子查询必须有别名
WHERE avg_salary > (SELECT AVG(salary) FROM Employees);在
FROM
DepartmentAvgSalary
3. SELECT子句中的标量子查询:丰富主查询结果
-- 查询每个员工的姓名,以及他所属部门的平均工资
SELECT
e.employee_name,
e.salary,
(SELECT AVG(salary) FROM Employees WHERE department_id = e.department_id) AS department_avg_salary
FROM Employees e;这种写法,我用得也挺多的。它允许你在主查询的每一行结果中,都带上一个与当前行相关的计算值。但有个坑要注意:如果子查询返回了多行,SQL会报错。所以,它必须是一个“标量”子查询,即只返回一个单一值。如果子查询涉及的计算量很大,或者被主查询调用了非常多次(比如主查询结果集很大),性能可能会成为问题。
4. EXISTS/NOT EXISTS子句:存在性判断的利器
-- 找出至少有一笔订单的客户 SELECT c.customer_name FROM Customers c WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.customer_id = c.customer_id); -- 找出没有任何订单的客户 SELECT c.customer_name FROM Customers c WHERE NOT EXISTS (SELECT 1 FROM Orders o WHERE o.customer_id = c.customer_id);
EXISTS
NOT EXISTS
IN
TRUE
SELECT 1
SELECT *
EXISTS
子查询固然方便,但用不好也容易埋下性能隐患。我在调优时,最常遇到的问题就是子查询导致查询速度变慢。识别和解决这些瓶颈,我觉得主要从以下几个方面入手:
1. 警惕关联子查询(Correlated Subquery)
关联子查询是指子查询的执行依赖于外部查询的每一行数据。它会为外部查询的每一行数据执行一次。就像上面
SELECT
解决方案:
重写为JOIN: 这是最常见的优化手段。很多关联子查询都可以通过
JOIN
GROUP BY
-- 优化前(关联子查询)
SELECT
e.employee_name,
e.salary,
(SELECT AVG(salary) FROM Employees WHERE department_id = e.department_id) AS department_avg_salary
FROM Employees e;
-- 优化后(JOIN + GROUP BY)
SELECT
e.employee_name,
e.salary,
da.department_avg_salary
FROM Employees e
JOIN (
SELECT department_id, AVG(salary) AS department_avg_salary
FROM Employees
GROUP BY department_id
) AS da ON e.department_id = da.department_id;这个重写后的版本,子查询(现在是派生表)只执行一次,然后结果与主表连接,效率通常会高很多。
2. 关注IN
当
WHERE column IN (SELECT ...)
解决方案:
尝试使用EXISTS
IN
EXISTS
IN
-- IN (可能效率低) SELECT customer_name FROM Customers WHERE customer_id IN (SELECT customer_id FROM Orders WHERE order_date >= '2023-01-01'); -- EXISTS (通常更高效) SELECT c.customer_name FROM Customers c WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.customer_id = c.customer_id AND o.order_date >= '2023-01-01');
重写为JOIN: 很多
IN
JOIN
-- IN SELECT customer_name FROM Customers WHERE customer_id IN (SELECT customer_id FROM Orders WHERE total_amount > 1000); -- JOIN SELECT DISTINCT c.customer_name FROM Customers c JOIN Orders o ON c.customer_id = o.customer_id WHERE o.total_amount > 1000;
DISTINCT
3. 利用索引优化子查询
子查询内部的查询,如果涉及的列没有合适的索引,同样会慢。
解决方案:
SELECT customer_id FROM Orders WHERE total_amount > (SELECT AVG(total_amount) FROM Orders)
Orders
total_amount
EXPLAIN
EXPLAIN
子查询和
JOIN
何时倾向于使用子查询:
WHERE salary < (SELECT MAX(salary) FROM Employees)
EXISTS
JOIN
DISTINCT
COUNT
FROM
何时倾向于使用JOINs:
JOIN
JOIN
JOIN
SELECT
JOIN
JOIN
我的个人经验是:
JOIN
JOIN
EXPLAIN
JOIN
最终,选择子查询还是
JOIN
以上就是SQL中的子查询是什么?嵌套查询的写法与优化技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号