首页/数据/数仓建模速查/累积快照的原地更新实现
维度与事实设计149 条

累积快照的原地更新实现

累积快照随流程推进更新同一行:用 MERGE 或「全分区重写」实现幂等更新,里程碑时间戳只允许从空到有、不可回退。

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

累积快照的更新方式

累积快照里一行代表一个业务实例(一张订单、一笔贷款申请)的完整生命周期,随着流程推进不断更新同一行的里程碑列。它和事务事实表正好相反:行数不随事件数量增长,而是同一行被反复改写。两个硬约束:里程碑时间只允许从空到有、不允许回退;更新必须幂等,同一批数据重跑不能把已完成的节点写回空值。

基本信息

粒度一个业务实例一行
更新实现MERGE 更新,或整分区重写
里程碑列下单、支付、发货、签收等时间戳
核心约束时间戳单调,只从空到有
幂等要求同批重跑,已完成节点不被覆盖

典型使用场景

  • 订单履约时效:从下单到签收各段耗时,一行即可算完
  • 信贷审批流程:各审核节点时间戳与停留时长
  • 工单处理链路:受理、派单、处理、关闭的流转分析
  • 物流节点跟踪:揽收、中转、派送、签收的时间序列
  • 转化漏斗:同一实例是否走到下一步,判断流失环节

MERGE 更新

MERGE 更新
-- 用 coalesce 保证已完成节点不被后到的空值覆盖
MERGE INTO fact_order_flow t
USING stg_order_flow s ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET
  t.pay_ts  = coalesce(t.pay_ts,  s.pay_ts),
  t.ship_ts = coalesce(t.ship_ts, s.ship_ts),
  t.sign_ts = coalesce(t.sign_ts, s.sign_ts),
  t.last_update_ts = s.update_ts
WHEN NOT MATCHED THEN INSERT VALUES
  (s.order_id, s.create_ts, s.pay_ts, s.ship_ts, s.sign_ts, s.update_ts);

关键列与异常

列含义异常表现
create_ts实例创建时间,应为非空为空说明源端字段缺失或首个节点未回传
pay_ts 等节点列首次到达该节点的时间补数被小值覆盖,耗时算成负数
last_update_ts最近一次被更新的时间不增长说明上游批次没跑到这张表
派生耗时列相邻节点时间差节点空值时不能直接相减,需置空
节点时间取首次到达的时间,不要取最后一次:取消后重新支付、发货后改单都会让时间戳后移,取末次会把真实的流程时效拉长。取消与关闭单加独立标记,不参与时效样本,否则平均值偏乐观。
并发写入同一行会互相覆盖里程碑:流任务与批任务同时更新同一批订单时,必须约定只有一个写入方,或用乐观锁(按 last_update_ts 版本号)控制,否则会出现节点丢失。

易错点

  • 时间戳被后续批次的小值覆盖:环节耗时出现负数,时效报表整列失真
  • 取消单混入时效样本:整体时效偏乐观,掩盖真实瓶颈
  • MERGE 条件只按业务键不含版本:并发写入互相覆盖,里程碑凭空消失
  • 派生耗时不统一在加载时生成:各报表各自相减,空值处理不一致
  • 未跟踪实例状态:已完成实例仍在被更新,行数不变但指标反复抖动

数据来源与参考

  • 数据仓库工具箱:累积快照事实表
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌