周测:JOIN 陷阱专项

月报交付。复盘这一周踩过的所有 JOIN 坑,来一场限时专项测评。

学 10 min
练 70 min
盘 40 min
共 120 分钟

复盘 · 10 min

  1. 01回看本周错题,重点看 JOIN 类

专项 12 题 · 110 min

  1. JOIN 之后 count 变多了,列出三种可能原因
    参考答案

    三种原因:① 一对多放大--连了 order_items 这类明细表,行数由「多」的一端决定;② 连接条件漏写或恒真(如 user_id = user_id),退化成笛卡尔积,行数 ≈ 两表行数之积;③ 右表连接列不唯一,本该一对一的关系实际是一对多。排查顺序:先笔算期望行数,再看 EXPLAIN 的估行数。

  2. 一对多连接导致订单金额被重复累加,写出两种修复方案
    参考答案

    方案一:先聚合再连接--CTE/子查询里按 order_id 把明细 sum 成「每单一行」,再 join 回 orders 做聚合;方案二:不连明细,直接用 orders.total_amount(seed 的 §B④ 已把它对齐成明细之和)。口述要点:重复累加的根源是「左表的列被多端的行重复携带」,先压缩多端就消掉了。

  3. 用三种写法查「没有下过单的用户」并对比计划
    参考答案

    三种写法:LEFT JOIN + o.id IS NULL(Hash Left Join,不用去重,大数据量通常最快);NOT EXISTS(优化器常改写成 anti join,计划和 LEFT JOIN 版几乎一样);EXCEPT(两边先去重再做集合减法)。EXPLAIN 对比三种节点,结论写进 notes.md。

  4. LEFT JOIN 后 count(b.id)count(*) 结果不同,解释原因
    参考答案

    LEFT JOIN 匹配不上时左行保留、右侧全 NULL:count(*) 数行,NULL 行也算 1;count(右表.非空列) 跳过 NULL。差值 = 没匹配上的左行数,「没下单显示 0」就是靠它实现的。

  5. 剩余 8 题:LeetCode 中等难度多表题
    参考答案

    选题集中在 INNER/LEFT JOIN、多表 GROUP BY、HAVING--正是本周标「高频」的内容。限时内做完;错题沿用第一周的归因法分三类(没懂概念 / 记不住语法 / 看错题意)记进 mistakes.md。

过关标准 12 题正确 ≥ 9 题;能画图解释一对多连接的金额翻倍问题。