考察点
宽表是数仓面试的高频题,考的是你对「空间换时间」这个数仓基本权衡的理解深度。面试官不想听「宽表好,查询快」这种一面之词,想听你能把收益和代价两边都摆出来,并且给出建宽表的决策标准。追问常落在「字段膨胀怎么办」「维度变了宽表怎么回刷」。
参考答案
宽表解决了什么问题
宽表是把事实和相关维度属性提前 join 好、打平成一张列很多的表。它的收益非常具体:
第一是查询性能。星型模型下查一次「各类目支付金额」要事实表 join 商品维、类目维,数据量大时 shuffle 开销明显;宽表里类目就是普通列,where + group by 直接出结果。在 ClickHouse、Doris 这类列存引擎上,宽表配合列裁剪和物化视图,性能优势更明显。
第二是口径统一和使用门槛。分析师和 BI 工具不需要懂表间关联关系,一张表拖字段就能用,「用户等级」不会有人 join 错维度版本。对自助分析场景,这是决定性的体验差距。
第三是把 join 成本从查询侧挪到计算侧。join 只做一次(ETL 时),而不是每个查询各做一次,总资源消耗往往更省。
代价同样具体
存储冗余:维度属性在每一行重复,一张用户日汇总宽表带上几十个维度属性,存储可能膨胀数倍。列存加压缩能缓解,但量级摆在那。
回刷成本高,这是最痛的一点。维度变了——比如类目体系调整、用户标签逻辑改了——宽表对应列要全量重算。维度越靠后越容易变,一张挂 20 个维度的宽表,每月总有几个维度在改,回刷成了常态。明细层(DWD)窄表就稳得多,事实本身几乎不变。
变更僵硬:加一个维度属性要改表结构、改任务、刷历史。如果宽表被几十个下游引用,变更还要协调下游窗口期,一次加字段走一周很常见。
字段膨胀失控:宽表没有天然边界,业务方不断「再加一个字段」,两年涨到几百列,没人知道哪些字段还有人在用,没人敢删,维护变成灾难。
时效性被最慢的依赖拖垮:宽表要等所有上游维表就绪才能跑,产出时间取决于最晚的那个依赖。
决策标准:什么时候该建
| 维度 | 适合宽表 | 不适合宽表 |
|---|---|---|
| 分层 | DWS/ADS,服务固定场景 | DWD 明细层,要保持稳定和灵活 |
| 需求形态 | 高频、模式固定的报表和看板 | 探索性分析、需求天天变 |
| 维度稳定性 | 维度口径成熟稳定 | 维度逻辑还在频繁迭代 |
| 数据规模 | 明细量大、join 成本显著 | 数据量小,join 无所谓 |
工程实践上还有几条纪律:宽表字段数设上限(比如 100 列),超了先治理再加;每个字段登记负责人和使用方,定期清理无人用的字段;维度属性优先退化「高基数查询高频用」的,低频的留外键 join;历史分区回刷用 insert overwrite 按分区覆盖,保证幂等可重跑。
可能的追问
- 宽表字段膨胀到几百列了怎么治理? 先用血缘和查询日志统计字段使用频率,零使用的字段走下线流程;再按主题拆表,把一张全能宽表拆成几张主题宽表(流量、交易、用户),用主键可关联。
- 维度历史变更后宽表怎么刷? 看变化性质:口径修正类全量回刷受影响分区;类目体系改版类通常只刷生效日之后的数据,之前的保留旧口径并在数据字典标注,避免历史报表数字突变。
- 为什么不直接在查询引擎里建视图代替宽表? 逻辑视图不解决 join 成本,每次查询都重算。物化视图可以,本质是把宽表交给引擎托管,在 Doris、ClickHouse 上是更省心的选择。