vault backup: 2026-05-21 12:20:54
This commit is contained in:
@@ -36,10 +36,13 @@ graph BT
|
||||
|
||||
```sql
|
||||
-- 用法 1:在 SELECT 中调用
|
||||
SELECT
|
||||
SELECT
|
||||
username,
|
||||
(SELECT COUNT(*) FROM orders WHERE user_id = users.id) AS order_count
|
||||
FROM users;
|
||||
-- 副作用:这个查询其实也是"相关子查询"的典型例子
|
||||
-- 因为内层的 user_id = users.id 引用了外层表的列
|
||||
-- 每一行 users 的记录都会触发一次内层查询
|
||||
|
||||
-- 用法 2:在 WHERE 中等价于常量
|
||||
SELECT * FROM products
|
||||
@@ -50,6 +53,10 @@ INSERT INTO reports (month, order_total)
|
||||
VALUES ('2026-05', (SELECT SUM(amount) FROM orders WHERE MONTH(created_at) = 5));
|
||||
```
|
||||
|
||||
> [!QUESTION] 上面用法 1 的子查询,每一行都要重新执行吗?
|
||||
> 是的——但不是因为"放在 SELECT 里",而是因为它引用了外层的 `users.id`。
|
||||
> 这就引出了子查询最重要的分类维度:**相关 vs 无关**。
|
||||
|
||||
### 相关 vs 无关子查询
|
||||
|
||||
这是理解子查询性能的基石:**子查询是否引用了外层查询的列?**
|
||||
@@ -436,6 +443,14 @@ WITH RECURSIVE org_chain AS (
|
||||
SELECT * FROM org_chain ORDER BY level, name;
|
||||
```
|
||||
|
||||
> [!QUESTION] 为什么叫「自我引用」?递归 CTE 到底怎么执行的?
|
||||
> `org_chain` 这个名字在定义内部就被引用了——`FROM employees e INNER JOIN org_chain oc`。
|
||||
> 第一轮:只执行锚点成员,得到根节点(CEO);
|
||||
> 第二轮:用第一轮的结果去 JOIN employees,得到 CEO 的直接下属;
|
||||
> 第三轮:用第二轮的结果去 JOIN,得到下属的下属……
|
||||
> 直到某一轮 JOIN 结果为空,递归自动终止。
|
||||
> **关键:没有终止条件 → 无限循环 → 触发 `cte_max_recursion_depth` 报错。**
|
||||
|
||||
> [!WARNING] 递归 CTE 的注意事项
|
||||
> - MySQL 默认递归深度上限为 **1000**(`cte_max_recursion_depth`),超出会报错
|
||||
> - 务必设置合理的终止条件,否则会无限递归直到达到上限
|
||||
@@ -466,6 +481,16 @@ SELECT * FROM org_chain ORDER BY level, name;
|
||||
> **子查询不是万能的——它首先是为了表达清晰,其次才是性能。**
|
||||
> 写完后务必跑 `EXPLAIN`,确认没有意料之外的临时表或多表扫描。当数据量上去后,能改写成 JOIN 的子查询就尽量改写,因为 JOIN 的执行路径对 Optimizer 更加透明。
|
||||
|
||||
> [!TIP] 学习路径建议
|
||||
> 如果你刚接触子查询,建议按这个顺序学习:
|
||||
> 1. **标量子查询** → 先理解「子查询就是一次独立的 SELECT」
|
||||
> 2. **相关 vs 无关** → 理解执行次数差异(本文核心概念)
|
||||
> 3. **IN vs EXISTS** → 掌握两种过滤范式,重点理解 NOT IN 陷阱
|
||||
> 4. **派生表** → 子查询作为虚拟表,理解物化与 Flattening
|
||||
> 5. **CTE** → 用现代语法重写派生表,最终挑战递归 CTE
|
||||
>
|
||||
> 每一步都要跑 `EXPLAIN` 看执行计划——**看懂 EXPLAIN 比背语法重要十倍**。
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[hhs/MySQL/02-SQL核心/08-DQL SELECT 全解析]] — SELECT 执行顺序与子查询的关系
|
||||
|
||||
Reference in New Issue
Block a user