订阅更新

商品价格每天都在变,你怎么设计这张维度表?

Hive手册 第 3 题 约 3 分钟读完

本文目录
  1. 先说结论
  2. 业务场景:短剧平台的商品价格表
  3. 实现SQL(用MERGE INTO)
  4. 面试高频追问:查询时怎么关联事实表?
  5. 总结

先说结论

缓慢变化维有三种处理方式:

Type 1(直接覆盖): 新值直接覆盖旧值,不保留历史。最简单但丢失了变更历史。

Type 2(新增行): 每次变更新增一行,用start_date/end_date标记有效期。生产环境最常用。

Type 3(新增列): 加一列存旧值。只能跟踪一次变更,很少用。

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

详细讲解

缓慢变化维(SCD)是数仓建模的核心问题,也是区分“会写SQL”和“懂建模”的分水岭。很多人知道Type 1/2/3的定义,但问到“具体怎么实现”就卡住了。今天用一个真实的商品价格场景来讲透。

业务场景:短剧平台的商品价格表

我们公司的短剧商品有币种、定价策略的变化。比如同一个短剧在不同地区价格不同,而且运营经常调价。我用的是Type 2:

CREATE TABLE dim_product (
  product_id    STRING,
  product_name  STRING,
  price         DECIMAL(10,2),
  currency      STRING,
  region        STRING,
  start_date    STRING,
  end_date      STRING,     -- '9999-12-31'表示当前有效
  is_current    BOOLEAN     -- 快速过滤当前有效版本
)
STORED AS PARQUET;

每当价格变更时:

1. 把旧记录的end_date从'9999-12-31'更新为昨天的日期,is_current设为false

2. 插入一条新记录,start_date为今天,end_date为'9999-12-31',is_current为true

实现SQL(用MERGE INTO)

-- 每天的增量更新逻辑
-- Step 1: 关闭已变更的旧记录
UPDATE dim_product
SET end_date = '2025-03-14', is_current = false
WHERE product_id IN (SELECT product_id FROM stg_product_update)
  AND is_current = true;
 
-- Step 2: 插入新版本
INSERT INTO dim_product
SELECT product_id, product_name, new_price, currency, region,
       '2025-03-15' AS start_date,
       '9999-12-31' AS end_date,
       true AS is_current
FROM stg_product_update;

如果用Delta Lake或Iceberg,可以直接用MERGE INTO一条语句搞定,代码量少很多。

面试高频追问:查询时怎么关联事实表?

用事实表的业务日期和维度表的有效期区间做关联:

SELECT f.order_id, f.amount, d.price, d.currency
FROM fact_order f
JOIN dim_product d
  ON f.product_id = d.product_id
 AND f.order_date >= d.start_date
 AND f.order_date < d.end_date;

这样每笔订单都能关联到下单时刻的正确价格,而不是当前价格。这就是Type 2的核心价值。

总结

记住一句话:Type 2是生产环境最常用的SCD方案,核心是start_date/end_date + is_current。面试的时候能用一个真实场景说清楚“为什么选Type 2”和“具体怎么实现”,就很稳了。

下一篇聊一个每个ETL开发都会遇到的问题:Hive小文件太多怎么办?查询慢得要命。

你们的维度表用的是哪种SCD方案?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器