mysql执行SQL时如何处理子查询_mysql子查询执行步骤解析

来源:这里教程网 时间:2026-02-28 20:45:46 作者:

子查询在 MySQL 中是先执行还是后执行?

MySQL 执行含子查询的 SQL 时,并不总是“先内后外”。它会根据子查询类型、是否相关、优化器判断,决定是物化(Materialize)、转为连接(JOIN),还是延迟执行。简单

SELECT
中的非相关标量子查询(如
(SELECT COUNT(*) FROM t2)
)通常会被提前计算一次;但出现在
WHERE
中的关联子查询(如
WHERE id IN (SELECT user_id FROM orders WHERE orders.user_id = users.id)
)可能对每行外层数据都重新执行——除非被优化器重写为半连接(semi-join)。

如何判断子查询是否被优化器重写?

EXPLAIN
查看执行计划是最直接的方式。重点关注以下几点:

type
列出现
ALL
+
Extra
Using where; Using join buffer
,大概率是未优化的嵌套循环式执行
Extra
出现
Start temporary
End temporary
,说明子查询被物化成临时表
select_type
显示
DEPENDENT SUBQUERY
表示关联子查询,
SUBQUERY
表示非关联
Extra
FirstMatch(users)
LooseScan
,说明已转为半连接优化

哪些写法会让子查询性能急剧下降?

这些常见写法极易触发低效执行路径:

WHERE
中使用
NOT IN (subquery)
且子查询结果含
NULL
:导致整个条件恒为
UNKNOWN
,常被误判为全表扫描
SELECT * FROM t1 WHERE id = (SELECT id FROM t2 WHERE ...)
但子查询可能返回多行:运行时报错
Subquery returns more than 1 row
SELECT
列表中写关联标量子查询,如
(SELECT name FROM dept WHERE dept.id = emp.dept_id)
:MySQL 8.0 前无法物化,每行都查一次
子查询里含
ORDER BY + LIMIT
却没加
GROUP BY
或确定性排序依据:结果不可靠,且优化器难做等价改写

替代子查询的更稳写法有哪些?

多数场景下,JOIN 或窗口函数比子查询更可控、更易优化:

WHERE x IN (SELECT y FROM t2)
改成
INNER JOIN t2 ON t1.x = t2.y
(去重需加
DISTINCT
或用
EXISTS
SELECT (SELECT MAX(time) FROM log l WHERE l.uid = u.id)
改成
LEFT JOIN (SELECT uid, MAX(time) AS last_time FROM log GROUP BY uid) l ON u.id = l.uid
MySQL 8.0+ 中,用
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)
替代“取每个分组最新一条”的相关子查询
避免在
UPDATE
/
DELETE
中直接引用同一张表的子查询,应套一层
SELECT
包装成派生表,否则报错
You can't specify target table for update in FROM clause

子查询逻辑清晰,但执行细节藏在优化器决策背后。真正影响性能的往往不是“有没有子查询”,而是“有没有索引支撑子查询的驱动条件”以及“优化器能否识别出等价 JOIN 形式”。别只盯着语法结构,多看

EXPLAIN
输出里的
rows
Extra
字段。

相关推荐