在数据库性能优化中,**子查询(Subquery)**往往是慢查询的重灾区。调优的核心思路是:减少嵌套、减少重复执行、利用索引、让优化器更容易生成高效执行计划。
下面按「常见类型 + 优化手段 + 示例」系统说明。
关联子查询(Correlated Subquery)
SELECT *
FROM orders o
WHERE o.amount > (
SELECT AVG(amount)
FROM orders o2
WHERE o2.customer_id = o.customer_id
);
IN 子查询返回大量数据
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM logs);
子查询无法使用索引
SELECT 列中子查询导致执行计划不稳定
SELECT *
FROM orders o
WHERE o.amount > (
SELECT AVG(amount)
FROM orders o2
WHERE o2.customer_id = o.customer_id
);
SELECT o.*
FROM orders o
JOIN (
SELECT customer_id, AVG(amount) avg_amt
FROM orders
GROUP BY customer_id
) t ON o.customer_id = t.customer_id
WHERE o.amount > t.avg_amt;
✅ 优势:
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM logs);
SELECT *
FROM users u
WHERE EXISTS (
SELECT 1
FROM logs l
WHERE l.user_id = u.id
);
✅ 原因:
WITH avg_amount AS (
SELECT customer_id, AVG(amount) avg_amt
FROM orders
GROUP BY customer_id
)
SELECT o.*
FROM orders o
JOIN avg_amount a ON o.customer_id = a.customer_id
WHERE o.amount > a.avg_amt;
✅ CTE(MySQL 8+ / PostgreSQL / Oracle):
SELECT
id,
(SELECT COUNT(*) FROM logs l WHERE l.user_id = u.id) AS cnt
FROM users u;
SELECT u.id, COUNT(l.user_id) AS cnt
FROM users u
LEFT JOIN logs l ON u.id = l.user_id
GROUP BY u.id;
重点关注:
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE INDEX idx_logs_user ON logs(user_id);
LIMITSELECT *
FROM users
WHERE id IN (
SELECT user_id
FROM logs
WHERE create_time > NOW() - INTERVAL 7 DAY
);
SELECT *
FROM (
SELECT *,
AVG(amount) OVER (PARTITION BY customer_id) avg_amt
FROM orders
) t
WHERE amount > avg_amt;
✅ 性能通常优于嵌套子查询
| 数据库 | 建议 |
|---|---|
| MySQL | 避免关联子查询,优先 JOIN |
| PostgreSQL | 可用 CTE / 窗口函数 |
| Oracle | 可用 WITH / 分析函数 |
| SQL Server | 查看实际执行计划 |
✅ 是否能改成 JOIN
✅ 是否可用 EXISTS
✅ 是否避免 SELECT 子查询
✅ 是否使用索引
✅ 是否减少返回行数
✅ 是否查看执行计划
如果你有 具体 SQL / 数据库类型 / 执行计划,我可以直接帮你改写到最优版本。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。