FDE Times 数据在招 FDE 职位 862▼55 近 7 天在招职位数的变化(同口径比较):不计入本周新开始追踪的公司的职位近 7 天新增 70在招公司 180支持远程 24%美国薪资中位数 $200k招聘最多 Palantir 95
ENVI

前线部署工程师(FDE)的专业媒体

书籍与课程

没人动过代码,上季度的数字为什么变了

Kimball 的《数据仓库工具箱》早已点明其中机制,dbt snapshots 至今仍在实现他的 Type 2 方案。

封面: The Data Warehouse Toolkit: The Definitive Guide to Dimensional Modeling
The Data Warehouse Toolkit: The Definitive Guide to Dimensional Modeling · Ralph Kimball · 封面图片:Open Library
分享微博

要点速览

  • Ralph Kimball 与 Margy Ross 合著的这本书(Wiley,2013 年)是维度建模的标准参考书,可以直接用在今天的 dbt 技术栈上。
  • SCD Type 1 覆盖旧值,历史随之消失;Type 2 新增一行并分配独立的代理键,每条事实都指向事件发生时有效的那个版本。
  • 值得带走的三点:先定粒度,有意识地为每个属性选择 SCD 类型,一致性维度只定义一次、所有人共用。
横向条形图,对比同一条 SQL 查询在三个时间点得到的北区第一季度销售额:上周为 1,000;执行 SCD Type 1 的 UPDATE、把客户 KH-07 的区域改掉之后为 700,因为 KH-07 的 300 挪到了南区;采用 SCD Type 2 时仍为 1,000。
一条 Type 1 的 UPDATE 让北区第一季度的数字少了 300。Type 2 新增一行维度记录,历史数字保持不变。来源:文中的假设示例,依据 Kimball Group 的 Dimensional Modeling Techniques 页面中的 SCD 技术。

设想一个周一早上。客户的销售负责人打开仪表盘,发现北区第一季度的收入比上周少了。没人改过数据管道,也没人删过订单。只是一个大客户把总部迁到了南区,系统就悄无声息地改写了过去。

如果你是负责这份数据的前线部署工程师(FDE),解释原因的人就是你。

这正是《数据仓库工具箱(第 3 版)》(The Data Warehouse Toolkit, 3rd Edition)以及 Kimball Group 发布的维度建模技术页面至今仍值得一读的原因。它们点明了让旧数字发生变化的机制,也说明了如何设计表结构,让这种变化只在你有意为之时才发生。

一本 2013 年的书,仍在描述今天的技术栈

Ralph Kimball 和 Margy Ross 合著了这本维度建模经典指南的第三版。维度建模是 Kimball 开创的方法,该书由 Wiley 于 2013 年出版。

书虽然不新,但 dbt 的官方文档至今仍把 snapshots 描述为在可能变化的源表上实现 SCD Type 2 的方式。Type 2 是 Kimball 提出的概念,dbt snapshots 只是把这一思路落成代码的一种方式。

所以,读 Kimball 让你明白 snapshots 解决的是什么问题,而不只是怎么配置。这些资料培养的 FDE 能力,是把模糊的业务问题转化为可以验证的数据设计。其中有三个思路,放到任何项目里都用得上。

画表之前,先定粒度

Kimball Group 的技术页面把粒度定义为事实表中一行数据代表什么。这是必须最先敲定的决策。听起来简单,但许多关于数字的争执正是从这里开始的。

比较“每行是一笔订单”和“每行是订单中的一件商品”。如果有人按行计数,两种粒度算出的“订单数”并不相同。在第二种粒度下,一笔包含三件商品的订单会被计为三次。

因此,到了客户现场,第一件事不是打开 SQL 编辑器,而是用业务语言把粒度写成一句话,请客户方的负责人确认。

覆盖旧值是一个决策,不是默认选项

回到周一早上的问题。在 SCD Type 1 下,新值直接替换维度行中的旧值。Kimball Group 的技术页面明确指出,这会抹掉历史。同一页面还提醒,所有受影响的聚合事实表和 OLAP 多维数据集都必须重新计算。

看看那个仪表盘背后的查询:

SELECT c.region, SUM(f.amount) AS revenue
FROM fact_orders f
JOIN dim_customer c ON f.customer_key = c.customer_key
WHERE f.order_date BETWEEN '2025-01-01' AND '2025-03-31'
GROUP BY c.region;

(revenue 即“收入”;下表中的“北区”“南区”分别对应 North 和 South。)

假设上周北区的数字是 1,000,其中 300 来自客户 KH-07。执行一条 Type 1 语句,例如 UPDATE dim_customer SET region = 'South' 之后,同一个查询会让北区变成 700,那 300 挪到了南区。如果按区域汇总的聚合表没有重算,它仍显示 1,000,两个仪表盘就对不上了。

Type 2 的做法不同。它在维度表中新增一行,写入更新后的值,并分配一个新的代理键,事实表随后用这个键作为外键。Kimball Group 建议至少增加三列:生效日期、失效日期和当前行标志。示例中的客户维度表如下:

customer_key customer_id region 生效日期 失效日期 当前
101 KH-07 北区 2024-01-01 2025-06-30 N
245 KH-07 南区 2025-07-01 9999-12-31 Y

再跑一遍同样的 SQL。第一季度的订单仍然关联到键 101,北区依旧是 1,000。7 月以后的订单则指向键 245。

Kimball 在 2008 年的一篇文章里拿自己举例:按照 Type 2,应当为 Ralph Kimball 新建一条员工记录,自 2008 年 7 月 18 日起生效,而不是修改旧记录。

并非每一列都需要 Type 2。修正拼错的客户名称时,覆盖旧值完全合理。你要做的是逐个过一遍属性,问客户:过去的报表应该显示当时的值,还是现在的值?

定义一次,处处复用

如果销售和财务各自维护一张“客户”表,双方的仪表盘很少能对得上。Kimball Group 给出的答案是一致性维度:与公司负责数据治理的人一起定义一次,然后在各个事实表之间复用。数字因此保持一致,后续开发成本也更低。

判断两个维度是否一致,有明确的标准:它们的属性必须使用相同的列名和相同的取值域。一张表写“North”、另一张写“N”,就不算一致。

按问题读,不必从头读到尾

可以试试这样一条路径:打开 Kimball Group 的 Dimensional Modeling Techniques 页面,依次阅读 Grain、Type 1、Type 2 和 Conformed Dimensions 这几节。之后遇到实际案例,再用书深入对应的主题。最后打开 dbt snapshots 文档,把理论和代码对上。

这些资料适合 SQL 写得不错、却从未对高管据以决策的数字负过责的开发者。

简历上写一句“用 dbt snapshots 将客户维度改为 SCD Type 2,客户更换区域时历史报表保持不变”,远比“精通 SQL”有分量。

客户很少问你用的是 Type 1 还是 Type 2,他们问的是:为什么昨天的数字和今天不一样?能在五分钟内讲清楚这一点的 FDE,接下来的每个问题都会被托付给他。

这篇文章对你有帮助吗?

7 个信源
路线图上的下一篇 · 阶段 2: 全栈工程能力四年过去,Joe Reis 几乎不想改写他的数据工程书工具几经更替,书中六条“暗流”仍是 FDE 初见客户时该带上的问题。