有道题看着像考 SQL:业务方说,我们要「每个用户最近 30 天的下单次数」,你给建张表吧。
不少候选人会立刻开始写 CREATE TABLE,字段列得很全。我一般会拦一下,先问两个问题:这张表一行是什么,以及这个口径以后还会不会被第二个人用。数据产品经理在这一层要交付的不是表结构,是口径的归属——同一句话被三份报表各写一遍 SQL,三个月后大概率出现三个不同的数,然后开会讨论谁是对的。
本系列第 5/10 篇 · 上一篇:A/B 实验题里最常见的四种错 · 下一篇:老板要一个驾驶舱,我先看决策现场
先声明粒度,再谈字段
「一行是什么」是我唯一会强制要求写进设计文档第一行的东西。
这个需求可以做成一行一个用户(带 30 天次数字段),也可以做成一行一个 user_id × stat_date(每天一次的滚动 30 天快照),还可以做成一行一个用户一天的下单明细,让上层自己聚合。三种都能算出那个数字,但能力完全不同:第一种只能回答「现在是多少」,第二种能画趋势、能回溯任意一天的口径,第三种最灵活但查询成本最高、口径最容易被上层各写各的。
粒度没定,后面的 join 全是隐患。用户维表如果是一对多(一个用户有多条等级变更记录),把它 join 到 user_id × stat_date 的汇总表上,行数会悄悄翻倍,而且通常没有任何报错——和第 3 篇里那类「没有报错的退化」是同一回事。所以设计里要写清楚维表如何取当前有效行、或按事件发生时的状态取历史版本。
还有几个必须在这一层拍板的口径:30 天是自然日还是滚动窗口,含不含今天;下单是创建订单还是支付成功;取消、退款、拆单、赠品算不算;跨时区按谁的日切。这些不是技术细节,它们决定这个数能不能和财务、和运营日报对得上。我习惯把每个字段写成一句人话定义,附一个「反例」——什么情况下这条记录不该被计入。
四层各自该干什么
分层不是为了整齐,是为了让改动只落在一层。
| 层 | 粒度 | 职责 | 我不允许发生的事 |
|---|---|---|---|
| ODS | 与源系统一致 | 原样落地,保留变更前后镜像 | 在这里清洗、去重、改字段名 |
| DWD | 一条业务事件一行 | 清洗、去重、统一 ID 与时间口径 | 在这里塞业务规则和政策口径 |
| DWS | 主题 × 统计粒度 | 按用户、商品、门店等做轻度汇总 | 为某个看板定制一堆专用字段 |
| ADS | 面向具体应用 | 宽表、指标结果、看板查询 | 把口径重新定义一遍 |
这套划分最实际的价值是复用与追责:支付成功这个口径只在 DWD 层定义一次,DWS 的用户日汇总基于它计算,ADS 只负责摆盘。哪天口径要改,改一处、评估下游、留一行变更日志,而不是在五个 SQL 里玩找不同。
工程上还有三件事我会追问。
幂等与回刷。分区按 dt 组织,任务重跑同一天必须得到同样的结果,不能靠「先删再插」之外还依赖外部状态。迟到数据是常态——客户端离线补报、支付回调延迟、退款几天后才发生,所以要约定回刷窗口:最近 N 天每天重算,窗口之外走单独的补数流程并留痕。窗口定多长取决于业务,不是越长越好,重算七天和重算九十天的代价差很多。
快照还是流水。用户等级、门店归属这类会变的属性,用「事件发生时的值」还是「当前值」,答案取决于问题。算历史月份的区域业绩,用当前归属会把门店迁移前后的业绩算给新区域。这类字段我倾向在事实表里冗余当时值,并在文档里写明它是快照,避免后来有人以为它能实时反映现状。
时效与成本。T+1 够不够,取决于这张表支撑的决策频率。日常经营复盘 T+1 完全够用,大促期间的库存和投放才需要实时链路,而实时链路的复杂度、成本和口径一致性代价都要单独核算。宽表冗余换查询速度,还是查询时 join 换存储,也按「谁能等、谁天天用」来定,不按技术偏好定。
什么时候我反而不建表
一次性取数、验证期的假设、只用一次的年度报告——这些我都不建表。先用一段带注释的临时 SQL 把数取出来,把口径和结果记在需求单里,等它第二次被用到,再沉淀成 DWS 层的一张正式表。
原因很实在:表一旦建了就有 owner、有调度、有下游依赖、有监控告警,还有一群人开始默认它永远正确。而早期需求的口径往往一个月内会改三次,每次改都要走一遍下游评估。我见过不少数仓里躺着一批「当时觉得以后会用」的表,没人敢删,也没人知道哪个还在被读,最后变成表坟场。
判断标准我总结成两句话:这个口径会不会被第二次使用,以及算错了谁负责。两个都答得上来,就正经建模、写字典、定 owner、加质量校验(行数波动、主键唯一、空值率);有一个答不上来,就先别让它进调度。
顺便说,面试里能主动提到「表也有下线机制」的人不多。字段血缘、最后访问时间、废弃公告、下线日期,这些不是数仓工程师的私事。数据产品的资产和别的产品功能一样,需要做减法,否则维护成本会慢慢吃掉所有新需求。
所以面对「建张表吧」,我的第一句还是:先告诉我,这一行代表什么。
评论