拉链表增量维护是什么
拉链表(缓慢变化维第二类)用生效起始日与失效日期记录属性变化轨迹:一个自然键在一段时间内只有一条有效记录。每日增量的维护动作固定为三步——找出与最新快照相比发生变化的实体、把旧版本的失效日期关闭到新版本起始日、插入新版本记录。首次用全量快照初始化,之后每天只处理变化行,因此维护成本与变更量成正比而非表规模。
基本信息
| 初始化 | 全量快照落一层:起始日为首次日期,失效日为极大值 |
|---|---|
| 变更检测 | 把最新快照与当前有效版本比对属性差异 |
| 关链 | 变化行的失效日期改为新版本起始日 |
| 开链 | 变化行插入一条新版本,失效日为极大值 |
| 日期约定 | 极大值常用 9999-12-31,读取时按 当期日期 过滤 |
| 幂等要求 | 重跑同一天必须先回到当天开始前的状态,或保证逻辑幂等 |
典型使用场景
- 用户属性历史:城市、等级变化轨迹,支持按当时状态分析
- 商品类目历史:类目调整后仍能按历史归属统计
- 组织架构历史:部门与汇报线变化,用于回溯某个时点的组织关系
- 合同或额度版本:记录生效区间的多次变更
- 审计追溯:回答「某天这个实体是什么状态」
变更检测、关链与开链
变更检测、关链与开链
-- 1) 变更检测:与当前有效版本比对属性差异
CREATE TABLE tmp_user_change AS
SELECT s.user_id, s.city, s.level
FROM ods_user_full s
JOIN dim_user_zip z ON s.user_id = z.user_id AND z.end_date = DATE '9999-12-31'
WHERE s.city <> z.city OR s.level <> z.level;
-- 2) 关链:整表重写,避免逐行 UPDATE 的成本
INSERT OVERWRITE TABLE dim_user_zip
SELECT user_id, city, level, start_date,
CASE WHEN user_id IN (SELECT user_id FROM tmp_user_change)
THEN DATE '2026-10-11' ELSE end_date END AS end_date
FROM dim_user_zip;
-- 3) 开链:为变化实体插入新版本
INSERT INTO dim_user_zip
SELECT user_id, city, level, DATE '2026-10-11', DATE '9999-12-31'
FROM tmp_user_change;按任意时点取当时状态
按任意时点取当时状态
-- 取 2026-09-15 生效的版本(区间为左闭右开)
SELECT user_id, city, level, start_date, end_date
FROM dim_user_zip
WHERE start_date <= DATE '2026-09-15'
AND end_date > DATE '2026-09-15';维护三步的检查点
| 步骤 | 检查什么 | 出错表现 |
|---|---|---|
| 变更检测 | 比对属性是否完整(新增字段要加入比对) | 新增字段变更不被捕获,历史缺失 |
| 关链 | 失效日等于新版本起始日 | 错开一天会留下无版本覆盖的空洞 |
| 开链 | 只插入变化实体,且日期正确 | 重复插入导致同一时点两个版本 |
| 重跑 | 先回滚或保证幂等 | 重复关链写坏区间,历史无法修复 |
区间取左闭右开(起始日包含、失效日不包含)能让相邻版本无缝衔接:读取时用 起始日 <= 目标日期 < 失效日,就不会出现当天没有版本的空白。
重跑当天任务时必须先回到当日开始前的状态,或把整个关链开链写成一次幂等的整表重写:直接重跑会重复关链,把已有区间改写坏,且很难逆向修复。