子查询(Subquery)在数据库中经常成为性能瓶颈,原因通常可以归结为执行方式、优化器限制、数据量和索引使用这几个方面。下面系统性地说明为什么子查询会慢,以及常见的慢点在哪里。
SELECT *
FROM orders o
WHERE o.amount > (
SELECT AVG(amount)
FROM orders o2
WHERE o2.customer_id = o.customer_id
);
问题:
✅ 优化方式:
JOIN + 聚合AVG() OVER())很多数据库(如 Oracle、MySQL)会尝试把子查询转成 JOIN:
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM orders);
如果优化器无法展开:
✅ 影响因素:
DISTINCT / GROUP BY / LIMIT / UNIONNOT IN + 可空字段WHERE x IN (SELECT y FROM t WHERE z > 10)
如果:
y 没索引z 没索引→ 子查询本身全表扫描
NOT IN 子查询特别慢WHERE id NOT IN (SELECT user_id FROM blacklist)
问题:
NOT EXISTS✅ 推荐:
WHERE NOT EXISTS (
SELECT 1 FROM blacklist b WHERE b.user_id = u.id
)
例如:
SELECT *
FROM (
SELECT * FROM logs ORDER BY create_time DESC
) t
LIMIT 100;
可能:
✅ 优化:
ORDER BY + LIMIT 放到最外层SELECT ...
FROM (
SELECT ...
FROM (
SELECT ...
FROM t
)
)
问题:
✅ 优化:
WITH)| 数据库 | 子查询特点 |
|---|---|
| MySQL | 5.x 对子查询优化弱,易全表扫 |
| PostgreSQL | 子查询优化较好,但仍怕相关子查询 |
| Oracle | 强,但复杂 SQL 易选错计划 |
| SQL Server | 通常能展开,但统计信息敏感 |
关注:
Nested Loop(尤其带子查询)MaterializeFilesortrows examined >> rows returnedWHERE / SELECT 中✅ 能用 JOIN 就别用子查询
✅ 相关子查询 → 窗口函数 / JOIN
✅ NOT IN → NOT EXISTS
✅ 子查询结果小 → 可物化
✅ 避免 SELECT 子查询(每行算一次)
如果你愿意,可以把具体的 SQL + 数据库类型 + 表结构发出来,我可以直接帮你改写得更快。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。