事实表追加与去重
事务事实表通常按业务发生时间分区、按分区整体覆盖写入,是数仓最基础的落地方式。真正的难点在于同一业务键在源端会多次到达:订单先创建后修改,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 拼接业务编号),否则任何重跑都会让行数翻倍,而且无法判断哪一行才是正确状态,只能整分区回滚重来。