首页/数据/数仓建模速查/事实表追加写入与去重
维度与事实设计149 条

事实表追加写入与去重

事务事实表按分区追加写入;同一业务键在源端可能多版本到达,入仓时按唯一键去重取末条,保证行粒度不重复。

数仓建模速查数据更新于 2026-10-13

事实表追加与去重

事务事实表通常按业务发生时间分区、按分区整体覆盖写入,是数仓最基础的落地方式。真正的难点在于同一业务键在源端会多次到达:订单先创建后修改,CDC 会推多条记录。若直接追加,同一订单会出现多行,金额与笔数指标被同步放大。标准做法是写入前按业务唯一键去重、按更新时间取末条,让表行粒度等于业务粒度。

基本信息

写入方式按分区 INSERT OVERWRITE,重跑覆盖同分区
去重键业务唯一键(订单号、流水号)
取数规则按更新时间取末条,末条并列时再按入库时间
幂等要求同日重跑任意次,结果行数与金额不变
验收口径count(*) 应等于 count(distinct 业务键)

典型使用场景

  • ODS 到 DWD 的日常加工:一天一批、一批一个分区,重跑不会产生重复行
  • CDC 增量入仓:同一记录多次变更到达,只保留当日最后一次状态
  • 上游补数重推:分区覆盖让补数与日常加载走同一条代码路径
  • 流批混用:流任务写当日分区,次日批任务整体重算覆盖
  • 数据修复:发现某天脏数据只需重跑该分区,其他日期不受影响

分区去重写入

分区去重写入
-- 同批去重后覆盖写入,重跑多次结果一致
INSERT OVERWRITE TABLE dwd_order PARTITION (dt = '2026-10-12')
SELECT t.order_id, t.user_id, t.amount, t.update_ts
FROM (
  SELECT o.*, row_number() OVER (
           PARTITION BY order_id
           ORDER BY update_ts DESC, op_ts DESC) AS rn
  FROM ods_order o WHERE o.dt = '2026-10-12'
) t WHERE t.rn = 1;

去重键怎么选

去重方式使用条件风险
业务唯一键源端保证键唯一键缺失时整行被判为未知
业务键加更新时间需要保留源端多版本下游必须再取一次末条
全字段比对仅用于内容完全重复的行金额被修正过的订单会被误删
分区键用业务发生时间而不是入库时间:迟到数据要落到它原本所属的日期,否则「按日查询」会同时漏掉旧日数据、污染当日数据。写入前先算一次去重前后行数差,差值异常放大说明源端重复推送或去重键选错了。
没有业务唯一键的表必须在上游补一个幂等键(如 trace_id 拼接业务编号),否则任何重跑都会让行数翻倍,而且无法判断哪一行才是正确状态,只能整分区回滚重来。

易错点

  • 按全字段去重:金额被修正过的订单要么都被删、要么都留下,指标不确定
  • 用入库时间而非业务更新时间排序取末条:数据乱序到达时取到的是中间状态
  • 去重键为空的行直接丢弃:关联不上维表的记录静默消失,总量对不上
  • 排序字段存在并列值又不加二级排序:每次重跑留下的行不同,结果不可复现
  • 分区用处理时间:迟到数据进错日期,历史分区被反复重写还查不到源头

数据来源与参考

  • 数仓工程实践:事实表幂等写入
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌