冗余字段解决什么问题
DWD 明细表如果每次取数都去关联维度表取门店名、类目名这类属性,同一份明细会被反复 join,扫描与 shuffle 成本层层叠加。常见做法是把高频且稳定的维度属性直接冗余进明细表,下游一次扫描就能拿到结果。代价是明细表变宽,且维表属性一旦变更,历史分区里的冗余值仍是旧值,必须在口径上说明清楚。
基本信息
| 适用层 | DWD 明细表(dwd_ 前缀,按 dt 分区) |
|---|---|
| 冗余对象 | 高频访问、变更很少的属性 |
| 只存键 | 频繁变更的属性(会员等级、门店归属) |
| 代价 | 表变宽 + 维表变更需回刷历史 |
| 判据 | 查询收益是否大于回刷成本与存储成本 |
典型使用场景
- 门店名、大区名、类目名:字典类属性多年不变,冗余后下游不必再 join
- 下单时点的门店归属:业务口径要求「谁卖的算谁」,只能在下单时固化
- 下游 BI 直连明细表:不接维表也能出报表,少一次关联就少一次风险
- 商品三级类目:把层级拼成一行,避免递归取父级类目
- 敏感属性不冗余:手机号、身份证冗余会把脱敏边界扩大到整张宽表
冗余拼接示例
冗余拼接示例
-- 明细左连维表,取维表当前有效版本
INSERT OVERWRITE TABLE dwd_trade_order_di PARTITION (dt='2026-10-12')
SELECT o.order_id,
o.store_id,
s.store_name, -- 冗余:下单时点门店名
s.region_name, -- 冗余:门店所属大区
o.pay_amt
FROM stg_trade_order o
LEFT JOIN dim_store s
ON o.store_id = s.store_id AND s.is_current = 1; -- 维表当前版本冗余判据对照
| 属性特征 | 处理方式 | 理由 |
|---|---|---|
| 字典类、长期不变 | 冗余进明细 | join 成本高于回刷成本 |
| 时点语义(下单门店) | 冗余并写明快照语义 | 事后无法补回 |
| 频繁变更(等级、状态) | 只存代理键 | 回刷代价高,读时再取 |
| 大字段(描述、图片地址) | 不冗余 | 放大存储与扫描量 |
| 敏感字段(手机号) | 不冗余并脱敏 | 避免扩大暴露面 |
冗余字段必须在注释里写清时点语义:是「下单时的门店名」还是「当前门店名」。二者在历史区间的数字并不一致,同名不同义是口径争议最常见的来源。
维表属性变更后回刷历史分区,会连带重算所有依赖该明细的下游表。回刷范围要事先评估并通知消费方,只改当天分区会让历史与当期对不上。