订阅更新

缓慢变化维(SCD)

数仓建模手册 第 3 题 约 5 分钟读完

本文目录
  1. 总结
  2. 什么是缓慢变化维?
  3. Type 1:直接覆盖(最简单)
  4. Type 2:拉链表(面试必考)
  5. Type 3:新增列(用得少)

总结

记忆点内容
SCD核心问题维度变了,历史要不要保留?
Type 1直接覆盖,丢历史,最简单
Type 2拉链表,保留完整历史,最常用
Type 3新增列,只存前一次值,极少用
拉链表三字段start_date / end_date / is_current
查询关键事实表日期落在维度的有效期范围内

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

基础 | 大数据面试 · 数仓建模系列

面试真题
用户换了手机号、商品改了价格,维度表怎么处理?请介绍SCD的几种类型,你们用的是哪种?

什么是缓慢变化维?

维度表的数据不是一成不变的。用户会改地址,商品会调价格,店铺会换名字——这些变化不频繁但确实会发生,就叫缓慢变化维(Slowly Changing Dimension)。

核心问题只有一个:变化了,历史数据要不要保留?不同的回答对应不同的SCD类型。

类型策略一句话总结
Type 1直接覆盖不要历史,只看最新
Type 2新增行(拉链表)完整保留历史,最常用
Type 3新增列只保留上一次的值

Type 1:直接覆盖(最简单)

用户换了手机号,直接UPDATE旧记录。简单粗暴,表永远只有最新状态。优点是简单,缺点是历史丢失,无法回溯「用户之前的手机号是什么」。适用于修正数据错误、不关心历史的场景。比如用户的昵称写错了,直接改就行,没必要保留错误的历史。

Type 2:拉链表(面试必考)

这是面试考得最多的类型,也是生产中最常用的方案。核心思路是:不改旧数据,新增一行,用start_date、end_date、is_current三个字段标记有效期。

举例:用户张三从手机号138xxxx改成139xxxx。变更前只有一条记录,变更后变成两条:旧记录的end_date改成变更日期前一天,is_current改成0;新增一行记录当前状态,end_date设为9999-12-31,is_current为1。

这样做的好处是,你可以查到任意历史时间点的用户状态。比如分析订单时,你想知道用户下单时的地址是什么(而不是现在的地址),就需要用拉链表做范围JOIN。

拉链表的三种查询姿势

-- 1. 查当前有效数据
SELECT * FROM dim_user WHERE is_current = 1;
-- 2. 查某个历史时间点的快照(2024年6月1日的状态)
SELECT * FROM dim_user
WHERE start_date <= '2024-06-01' AND end_date > '2024-06-01';
-- 3. 事实表关联历史维度(订单发生时用户的状态)
SELECT f.order_id, f.amount, d.phone, d.city
FROM fact_order f JOIN dim_user d
ON f.user_id = d.user_id
AND f.order_date >= d.start_date AND f.order_date < d.end_date;
Wood的实战经验
end_date的处理要统一,这是很容易踩的坑。有的团队用闭区间(end_date = '2025-01-14'),有的用开区间(end_date = '2025-01-15')。
我们团队统一用左闭右开(start_date <= 且 end_date >),和事实表的日期分区逻辑保持一致,能避免很多边界Bug。这个看似小的约定,实际上帮我们省了很多排查时间。
常见追问:拉链表数据量会不会膨胀?答案是:只有发生变化的行才新增记录,不变的行不增长。高频变化的维度(如实时价格)不适合拉链表,考虑快照表。

Type 3:新增列(用得少)

只关心「当前值」和「上一次的值」,加两列搞定(如current_city和previous_city)。优点简单不增加行数,缺点只保留一次历史,变化3次以上就丢数据了。极少使用。

面试加分提示
面试回答SCD时,不要只背Type 1/2/3的定义,要能说出你的实战选择和原因:
「我们主要用Type 2拉链表。比如用户维度表,用户可能改手机号、改收货地址,我们需要在分析订单时关联到下单时的用户状态,所以必须保留历史。拉链表用start_date/end_date做有效期标记,事实表通过订单日期和有效期做范围JOIN。」
追问防线:面试官可能追问「拉链表数据量会不会膨胀」——只有发生变化的行才新增记录;高频变化的维度不适合拉链表,考虑快照表;定期归档过老的历史数据,控制表大小。
刷题进度保存在当前浏览器