考察点
这道题出自字节跳动数据仓库工程师二面。二面比一面更偏实战,面试官默认你已经知道分层是什么,想听你真正优化过一个烂摊子数仓的思路:表太多、重复计算多、存储贵、产出慢,怎么下手。期望答案是体系化的——能从设计、存储、计算、治理四个维度展开,且每招都有落地细节。追问常往"怎么衡量模型好坏"、"怎么推动存量模型重构"、"宽表到底多宽算过宽"走。
参考答案
先建立度量:没有指标就没有优化
优化前先回答"什么叫好模型"。业界常用几个量化指标:复用度(下游表数量,DWS 表被 5 张以上下游引用才算及格)、穿透率(直接访问 ODS 的任务占比,这个比例高说明中间层失效了)、重复度(相似口径的表数量,用血缘和指标字典比对)、产出时效(核心链路 SLA 达成率)。先把这四个数拉出来,优化的优先级自然清晰:先治穿透率高的域,再砍重复表,最后压成本。
设计层面的优化
第一招是合并同类项。把血缘拉出来,凡是加工逻辑 80% 以上相似的表合并成一张,尤其是 ADS 层——很多团队一个需求一张表,几十张表算的是同一批指标的不同切片,合并成带维度组合的汇总表,计算量直接砍半。
第二招是宽表化与逆宽表化的平衡。高频共用的维度属性冗余进 DWD/DWS 宽表,下游不用反复 join,这是性能优化的主力手段。但宽表不是越宽越好:字段超过几百个后,新增字段要全量回刷历史分区,维护成本陡增。经验法则是只冗余"80% 的下游都会用到"的字段,长尾维度留在 DIM 表里让需要的任务自己 join。
第三招是粒度治理。检查 DWS 表粒度是否统一,同一个主题下"用户+天"和"用户+商品+天"两种粒度并存时,看后者能不能从前者聚合出来,能就砍掉细粒度表,用前者加一层轻聚合替代,省存储也省计算。
存储与计算层面的优化
存储格式统一收敛到列存(ORC/Parquet),配合压缩(Snappy 或 ZSTD),相比 textfile 通常能省 60% 以上的存储。分区设计要匹配查询模式:离线数仓按天分区是底线,超大表(日增量百亿行级)考虑二级分区(天+小时或天+业务线)。小文件治理是老生常谈但真省钱——merge 小文件任务定期跑,减少 NameNode 压力和 map task 数量。
生命周期管理直接挂钩成本:ODS 保留 3090 天(够回溯重算就行),DWD 保留 12 年,DWS 看业务需要,ADS 大多数 90 天。冷数据转冷存储或降副本。字节这种体量下,生命周期策略执行到位能砍掉可观比例的存储费用。
计算层面,核心链路任务做倾斜治理和资源调优(见倾斜专题);非核心任务错峰调度;T+1 链路里能增量化就不全量——比如 DWS 的"用户近 30 天行为"用滚动窗口每天增量更新,而不是每天重算 30 天全量。
口径与治理层面
模型混乱的根源往往是指标口径没人管。建立指标字典(原子指标 + 派生指标 + 修饰词的三段式定义),新指标先查字典再开发,从入口挡住重复建设。存量表做下线机制:血缘上 90 天无访问、无下游的表先打标冻结,再观察一个周期后物理删除,腾出资源也减少维护面。推动重构时别搞运动式治理,绑定新需求做——需求要动这张表时顺手把它的加工逻辑收敛到规范层,成本低阻力小。
一个实战例子
某电商域发现 ODS 穿透率 40%,排查后发现是 DWS 缺"商家维度"的汇总,所有商家侧需求都在自己从 DWD 聚合。补建商家 DWS 宽表后穿透率降到 10% 以内,下游任务平均时长降了一半,存储反而降了——因为几十个任务各自存的中间结果都清了。这个例子说明模型优化经常是"补一层"而不是"删一批"。
可能的追问
- 宽表加字段成本这么高,怎么平衡灵活性?高频维度进宽表,低频维度留 DIM 按需 join;真有大量稀疏维度需求,考虑用 map 类型字段或拆"扩展属性表"按需求横向关联。
- 怎么说服业务方配合下线下面的表?用数据说话:拉出血缘访问记录和成本账单,冻结期无人认领就删;同时提供替代表的迁移指引,降低切换成本。
- 增量化改造有什么坑?最典型的是迟到数据和维度回刷:历史分区被重算后增量结果不一致,需要周期性全量校准或者设计幂等的重算机制。