数据膨胀与JOIN陷阱
总结
| 记忆点 | 内容 |
|---|---|
| 膨胀根因 | JOIN键不唯一,多对多关联 |
| 三大场景 | 维度表主键重复、粒度不对齐、多对多JOIN |
| 排查四步 | 查唯一性 → 对比行数 → 定位Key → 确认粒度 |
| 预防手段 | ETL加行数校验卡点,膨胀自动告警 |
| 核心原则 | 每次JOIN前先确认粒度和主键唯一性 |
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
进阶 | 大数据面试 · 数仓建模系列
| 面试真题 你有没有遇到过JOIN之后数据行数变多的情况?是什么原因?怎么排查和解决的? |
|---|
数据膨胀:数仓开发的隐形杀手
这个问题看起来基础,但我敢说80%的数据开发都踩过这个坑,包括我自己。场景还原:你写了一个简单的JOIN,原表A有100万行,JOIN之后变成了150万行。金额加起来多了50%,报表数字全是错的。
根因只有一个:JOIN键不唯一,产生了多对多关联。
最常见的三种膨胀场景
场景一:维度表主键不唯一
最经典的坑。你以为dim_user的user_id是唯一的,但实际上:拉链表忘了加is_current = 1过滤;数据源有重复(上游没去重);全量和增量混跑,同一个ID有多条记录。
| Wood的实战经验 我之前遇到过一次:用户维度表的is_current标记有Bug,同一个user_id有两条current=1的记录,JOIN之后订单行数翻倍,GMV直接多算了一倍。当天报表就被业务方投诉了。 从那以后,我在维度表的ETL任务里加了主键唯一性校验——不通过就不写入下游。这一个小改动,避免了后续无数次类似的事故。 |
|---|
场景二:粒度不对齐
事实表粒度是「订单+商品」(一个订单3件商品=3行),你JOIN了一张「订单粒度」的优惠券表(一个订单1行),看起来没问题。但如果反过来,订单粒度的事实表JOIN了商品粒度的价格表,一个订单的3件商品各关联一条价格记录,就膨胀了。核心原则:JOIN之前先确认两边的粒度是否对齐。
场景三:多对多JOIN
最危险的情况。比如一个用户属于多个用户组、一个商品有多个标签、一个订单用了多张优惠券。本来两个订单300元,JOIN之后变成4行600元。如果你没发现,SUM(amount)直接错一倍。
防膨胀排查四步法
我总结的一套排查流程,写SQL前过一遍能避免90%的膨胀问题:
第一步:检查JOIN键唯一性。用GROUP BY join_key HAVING COUNT(*) > 1分别检查两侧。
第二步:对比JOIN前后行数。JOIN前COUNT(*)和JOIN后COUNT(*)对比,如果增长了就必有膨胀。
第三步:定位膨胀的Key。找到具体哪些Key导致了行数增加。
第四步:确认粒度对齐。画一张简单的表格:A表一行=什么,B表一行=什么,JOIN关系是一对一还是一对多?
| -- 检查维度表主键唯一性 SELECT user_id, COUNT(*) AS cnt FROM dim_user WHERE is_current = 1 GROUP BY user_id HAVING cnt > 1; -- 有结果说明主键不唯一,JOIN必膨胀 -- 对比JOIN前后行数 SELECT COUNT(*) FROM fact_order; -- 比如1000000 SELECT COUNT(*) FROM fact_order a JOIN dim_user b ON a.user_id = b.user_id; -- 如果 > 1000000,必有膨胀 |
|---|
| 面试加分提示 这题面试官想考的是你的数据质量意识和排查能力。高分回答要有具体案例: 「我遇到过一次,用户宽表的金额指标比源表多了将近一倍。排查后发现是用户维度表的拉链表没加is_current过滤,user_id有两条有效记录,JOIN导致行数翻倍。修复后我在ETL流程里加了一个质量卡点:每次JOIN之后自动校验行数,如果增长超过1%就告警,避免这类问题再次漏到下游。」 关键词:发现问题 → 定位原因 → 修复 → 预防机制。有闭环的回答才是好回答。 |
|---|