Skip to content

宽表 vs 星型何时用 ​

难度与前置

难度:进阶
前置:知道事实表/维表;写过 DWS 汇总或 ADS 报表 SQL;了解 数仓分层。
读完能做什么:按查询形态与变更频率在宽表、星型(及轻度冗余)之间选型,用成本与正确性清单验收,避免「一切皆宽表」或「一切皆星型」。

适用场景 ​

  • 主题域建模评审:订单、用户、流量是否打成一张宽表
  • ADS / 报表层 SQL 经常 5+ 表 Join,BI 同学抱怨难写
  • 维属性频繁变更,宽表回刷成本失控
  • 面试要讲清「维度建模 vs 宽表」的工程取舍,而不是背定义

不适用:

  • 仅讨论理论范式(3NF)而无查询与运维约束
  • 实时流内状态 Join(见 Flink 维表 / 状态 Join(专篇待开;状态侧可先看 State TTL))
  • 已有稳定星型且无性能/维护痛点——勿为改而改

真实场景(一条) ​

某电商 ADS「订单明细宽表」把用户等级、商品类目三级、渠道、优惠券规则共 40+ 维属性打平。BI 查询快,但维表类目每周调整:宽表全量回刷 6 小时,且历史订单「下单时类目」与「当前类目」口径混乱,导致同比异常。

改造:DWD 保留星型(事实 + 维快照键);ADS 仅对高频报表物化「查询宽表」,并固化「下单时维」快照列;低频分析走星型 Join。回刷缩到受影响分区,口径争议下降。

怎么做(步骤清单) ​

1. 先对齐两种形态在干什么 ​

形态典型落点优点代价
星型 / 雪花DWD~DWS维变更局部、口径清晰、存储省查询多 Join、对分析师不友好
宽表(打平)DWS~ADS查询简单、预关联性能稳维变更要回刷、膨胀、口径易糊
轻度冗余中间层保留键 + 少量高频属性需约定「快照时点」

口诀:稳定高频查询 → 可宽表;易变维 / 多口径 → 星型 + 按需物化。

2. 用「查询画像」决定默认形态 ​

收集 2~4 周真实查询(或 BI 看板 SQL),填表:

维度问题倾向
Join 深度是否经常 >3 表深 → 考虑物化宽表
过滤列是否总用同一批维属性是 → 可打进宽表
维变更频率类目/组织是否周级变高 → 星型或「下单时快照」
回刷窗口SLA 能否扛全量重算否 → 勿大宽表绑易变维
消费者BI 自助 vs 固定报表自助且复杂 → 星型文档 + 语义层
sql
-- 示意:从查询日志粗看「常 Join 的维」
SELECT dim_table, COUNT(*) AS cnt
FROM query_audit
WHERE dt BETWEEN '${d7}' AND '${d1}'
  AND sql_text RLIKE 'join\\s+dim_'
GROUP BY dim_table
ORDER BY cnt DESC
LIMIT 20;

3. 分层落位建议(与分层对齐) ​

  1. ODS:贴源,不纠结宽/星
  2. DWD:优先星型事实 + 维(或维键);事务过程保持可解释
  3. DWS:轻度汇总;可冗余稳定维属性(如城市等级)
  4. ADS:面向消费的宽表 / 主题表;一张表服务一类看板

详见 数仓分层实践。分区与回刷配合 分区策略、幂等回刷。

4. 宽表设计清单(决定做时) ​

  • 固化时点:每条事实带「下单时 / 支付时」维快照,禁止默默用「当前维」覆盖历史
  • 列裁剪:只打高频列;长尾属性走星型或侧车表
  • 主键与粒度:一行一业务粒度(订单行 / SKU 日),写进表注释
  • 分区:按业务日;维变更回刷只动受影响分区
  • 血缘:宽表 ← 事实 + 哪些维版本,登记在元数据
sql
-- ADS 宽表示意:事实 + 下单时维快照
INSERT OVERWRITE TABLE ads_order_wide_di PARTITION (dt = '${biz_date}')
SELECT
  o.order_id,
  o.user_id,
  o.sku_id,
  o.pay_amt,
  o.order_time,
  u.user_level_at_order,   -- 下单时快照,不是当前等级
  s.cate_l1_at_order,
  s.cate_l2_at_order,
  c.channel_name_at_order
FROM dwd_order_di o
LEFT JOIN dim_user_snap_di u
  ON o.user_id = u.user_id AND u.dt = '${biz_date}' AND u.snap_type = 'order_time'
LEFT JOIN dim_sku_snap_di s
  ON o.sku_id = s.sku_id AND s.dt = '${biz_date}' AND s.snap_type = 'order_time'
LEFT JOIN dim_channel_snap_di c
  ON o.channel_id = c.channel_id AND c.dt = '${biz_date}'
WHERE o.dt = '${biz_date}';

5. 星型设计清单(决定做时) ​

  • 事实表只留外键 + 度量 + 退化维(订单号等)
  • 维表独立;缓慢变化用 快照 vs 拉链 / SCD2
  • 提供语义层 / 视图降低 BI Join 成本,而不是强行宽表
  • 热点小维可 Broadcast,避免每次 Shuffle(见 Spark/Hive Join 文)
sql
-- 星型查询示意:事实 + 维,口径在维表版本上控制
SELECT
  d.cate_l1,
  SUM(f.pay_amt) AS pay_amt
FROM dwd_order_di f
JOIN dim_sku_zf d
  ON f.sku_id = d.sku_id
 AND f.order_time >= d.start_time
 AND f.order_time <  d.end_time
WHERE f.dt BETWEEN '${d_start}' AND '${d_end}'
GROUP BY d.cate_l1;

6. 混合策略(多数团队的现实答案) ​

模式做法
双轨DWD 星型为真源;ADS 物化 3~5 张高频宽表
延迟打平夜间物化宽表;白天分析走星型
属性分级P0 属性进宽表;P1 按需 Join;P2 仅主题域
变更隔离易变组织树不进订单宽表,单独组织主题表

7. 决策树(评审可投影) ​

text
查询是否固定且高频?
  ├─ 否 → 星型 + 文档/语义层
  └─ 是 → 维是否周级以上变更?
        ├─ 是 → 宽表只打「事件时快照」;易变维勿绑死
        └─ 否 → 可打平进 ADS 宽表;约定回刷范围
存储/回刷 SLA 是否吃得消?
  └─ 否 → 缩列或拆主题宽表,禁止「万能一张表」

8. 与指标口径的衔接 ​

宽表一旦把指标预计算进去(如「优惠后 GMV」),必须挂 指标口径一致性 文档:公式、是否含退款、时区。宽表不是口径的替代品。

常见坑(至少牢记这些) ​

  1. 一切皆宽表
    维一变全链路回刷;历史口径被「当前维」污染,同比失真。

  2. 一切皆星型却无语义层
    BI 每人写一套 Join,出现三套「GMV」;性能与口径双崩。

  3. 宽表用当前维覆盖历史
    类目调整后重刷把去年订单改到新类目,业务以为「数据错了」。

  4. 粒度没写清
    订单头与订单行混在一张「宽表」,SUM 直接翻倍。

  5. 雪花过深当星型
    五层维链 Join,优化器与人都痛苦;应扁平化常用路径或物化。

  6. 为「消除冗余」反范式清洗掉快照
    存储省了,审计与监管要的「当时画像」没了。

如何验收(可量化) ​

  • [ ] 选型文档写明:默认形态、例外宽表清单、快照时点约定
  • [ ] 宽表行数 = 声明粒度计数(抽样对账)
  • [ ] 维变更演练:只回刷约定分区,耗时 < SLA
  • [ ] 同口径指标:宽表结果 vs 星型 Join 结果偏差在阈值内(如金额相对差 < 0.1%)
  • [ ] BI 高频看板 SQL 平均 Join 表数下降或 P95 耗时下降(有基线)
sql
-- 粒度验收:宽表一行一订单行
SELECT
  COUNT(*) AS wide_cnt,
  COUNT(DISTINCT order_id, sku_id) AS grain_cnt
FROM ads_order_wide_di
WHERE dt = '${biz_date}';
-- 期望 wide_cnt = grain_cnt

-- 口径对账:宽表 GMV vs 星型
SELECT 'wide' AS src, SUM(pay_amt) AS gmv FROM ads_order_wide_di WHERE dt = '${biz_date}'
UNION ALL
SELECT 'star', SUM(f.pay_amt)
FROM dwd_order_di f
WHERE f.dt = '${biz_date}';
bash
# 回刷演练记录(示意)
echo "biz_date,mode,duration_min,partitions_touched"
# 2026-09-20,cate_change_restate,45,7

相关面试题 ​

占位:与题库小程序对齐后补链接(建议关联:维度建模、宽表利弊、SCD、指标口径、分层落位)。


改写说明:结构与判断标准参考 Wood 原创数仓/面试文,已改写成可执行清单;未包含未公开公司数据与内部表名。