周测:JOIN 陷阱专项
月报交付。复盘这一周踩过的所有 JOIN 坑,来一场限时专项测评。
复盘 · 10 min
专项 12 题 · 110 min
- JOIN 之后 count 变多了,列出三种可能原因
参考答案
三种原因:① 一对多放大--连了 order_items 这类明细表,行数由「多」的一端决定;② 连接条件漏写或恒真(如 user_id = user_id),退化成笛卡尔积,行数 ≈ 两表行数之积;③ 右表连接列不唯一,本该一对一的关系实际是一对多。排查顺序:先笔算期望行数,再看 EXPLAIN 的估行数。
- 一对多连接导致订单金额被重复累加,写出两种修复方案
参考答案
方案一:先聚合再连接--CTE/子查询里按 order_id 把明细 sum 成「每单一行」,再 join 回 orders 做聚合;方案二:不连明细,直接用 orders.total_amount(seed 的 §B④ 已把它对齐成明细之和)。口述要点:重复累加的根源是「左表的列被多端的行重复携带」,先压缩多端就消掉了。
- 用三种写法查「没有下过单的用户」并对比计划
参考答案
三种写法:LEFT JOIN + o.id IS NULL(Hash Left Join,不用去重,大数据量通常最快);NOT EXISTS(优化器常改写成 anti join,计划和 LEFT JOIN 版几乎一样);EXCEPT(两边先去重再做集合减法)。EXPLAIN 对比三种节点,结论写进 notes.md。
- LEFT JOIN 后
count(b.id)与count(*)结果不同,解释原因参考答案
LEFT JOIN 匹配不上时左行保留、右侧全 NULL:count(*) 数行,NULL 行也算 1;count(右表.非空列) 跳过 NULL。差值 = 没匹配上的左行数,「没下单显示 0」就是靠它实现的。
- 剩余 8 题:LeetCode 中等难度多表题
参考答案
选题集中在 INNER/LEFT JOIN、多表 GROUP BY、HAVING--正是本周标「高频」的内容。限时内做完;错题沿用第一周的归因法分三类(没懂概念 / 记不住语法 / 看错题意)记进 mistakes.md。