考察点
这是维度建模的基础对比题,面试官想听的不是两个名词的定义,而是选型背后的工程权衡:存储与 join 成本谁贵、查询性能和口径一致性怎么平衡。追问常问「维度层级(类目树、地区树)在星型模型里怎么处理」和「什么情况下雪花仍有价值」。
参考答案
两种模型的结构差异
星型模型:一张事实表居中,各维度表像角一样直接挂在事实表上,每个维度一张扁平的表,维度内部的层级(商品 → 一级类目 → 二级类目)全部打平进同一张维表。事实表到任何维度属性都是一跳 join。
雪花模型:在星型基础上对维表做范式化拆分。商品维表只留商品级属性,类目拆成 dim_category,地区拆成 dim_region,维表之间再用外键关联,整张图像雪花。事实表要拿一级类目,得先 join 商品表再 join 类目表。
| 对比项 | 星型 | 雪花 |
|---|---|---|
| 维表规范化 | 不打平,扁平冗余 | 范式化拆分,消除冗余 |
| 事实表 join 深度 | 1 跳 | 多跳 |
| 存储 | 维度属性冗余,占空间多 | 节省维表存储 |
| 查询性能 | join 少,快 | join 链路长,慢 |
| ETL 复杂度 | 维表构建简单 | 多级维表有依赖顺序 |
| 口径一致性 | 属性只有一份拷贝(在扁平表里) | 理论上更规范 |
为什么传统数仓时代有人选雪花
雪花的初衷来自关系型数据库时代:存储贵,规范化消除冗余能省空间;维度属性只存一份,修改时只改一处,避免更新异常。在 Oracle、DB2 这类单机或小型 MPP 库里,这套账是算得过来的。
但这套前提在大数据体系下基本失效。第一,HDFS 存储足够便宜,维度表相对事实表本来就是小表——一亿商品的商品维表打平后也就几十 GB,跟动辄 PB 级的事实流水比是零头,为省这点空间付出 join 成本不划算。第二,join 是大数据计算里最贵的操作,多一跳 join 就多一轮 shuffle,雪花模型把一个 join 变成两三个,查询时长可能成倍增加,而分析师写 SQL 时还要搞清楚维表之间的关联链路,出错率高。第三,Hive/Spark 生态的优化器(CBO、broadcast join)对星型结构支持最好,事实表 broadcast 维表是最成熟的加速路径。
所以结论很直接:离线数仓选星型,这是行业共识。阿里、美团的公开数仓实践里,DWD 层都是事实表 + 扁平维表,甚至更进一步把高频维度属性直接退化进事实表,连那一跳 join 都省掉。
维度层级在星型里怎么处理
反对星型的常见理由是「类目树经常调整,打平后改不动」。实际处理手法:类目层级作为属性冗余在商品维表里(category_id1/2/3、category_name1/2/3),类目调整时重刷商品维表即可——维表重刷是离线数仓的常规操作,T+1 任务顺手就做了。如果需要分析类目体系本身的变迁,单独建一张类目维表存层级关系,业务分析时按 ID 关联,这不构成雪花模型,只是多了一张维表。
雪花模型还活着的地方
不能说雪花一无是处。两类场景它仍有价值:一是维度属性本身构成独立分析主题,比如供应商维度和供应商的资质文件维度各有分析需求,拆开更清晰;二是某些 OLAP 引擎(老一代的 MOLAP、部分 BI 工具的语义层)对规范化结构支持更好。另外实时数仓里为减少状态存储,Flink 作业可能只保留键值维表,查询时再由 OLAP 引擎做关联补全,这算雪花的变体思路。但这些都是例外,回答时的立场应该清楚:默认星型,有明确理由才雪花。
可能的追问
- 星座模型(fact constellation)和它们什么关系? 多张事实表共享同一组维度表就是星座,这是真实数仓的常态——下单、支付、退款三张事实表共享用户、商品、日期维度,「共享维度」正是总线架构和一致性维度的基础。
- 星型模型的维度冗余不会导致口径不一致吗? 会有这个风险,靠治理手段解决:同一属性全公司只认一张权威维表,其他表的同名字段必须从这里同步,配合指标字典和数据血缘管控,而不是靠范式化从技术上杜绝。
- ClickHouse/Doris 里还坚持星型吗? 这些引擎单表扫描极快,实践上甚至更激进——直接打大宽表,把维度属性全预 join 进事实表,用列存压缩消化冗余。星型是底线,宽表是常见演进。