拉链表是什么
拉链表是 SCD Type 2 最常见的落地形态:一行等于实体在某个时间区间内的状态,用 start_date 与 end_date 描述有效范围,end_date 为极限日期(如 9999-12-31)表示当前有效。它按天增量维护、只存发生变化的部分,所以体积通常远小于每日全量快照,同时保留完整历史,是「既省空间又能回溯」的折中方案。
基本信息
| 结构 | 业务键 + 属性 + start_date + end_date |
|---|---|
| 当前有效 | end_date 为极限日期(如 9999-12-31) |
| 体积特征 | 只存变化,通常小于每日全量快照 |
| 使用方式 | 按日期区间条件取当天有效的行 |
典型使用场景
- 用户维度历史留存:按天比对新旧状态,只追加变化
- 商品与价格历史:需要按当时价格回溯成交分析
- 组织架构变更:支持按当时归属统计历史业绩
- 存储优化:替代每日全量快照,降低存储与计算成本
- 对账与审计:需要证明某个时间点实体的准确状态
取某一天的有效状态
取某一天的有效状态
SELECT user_id, city, level
FROM dim_user_zip
WHERE '2026-10-11' >= start_date AND '2026-10-11' < end_date; -- 左闭右开,避免命中两行每日增量维护要点
每日增量维护要点
-- 1) 变化实体:关闭旧版本(当前行 end_date 置为今日)
UPDATE dim_user_zip SET end_date = DATE '2026-10-11'
WHERE user_id IN (SELECT user_id FROM stg_user_changed) AND end_date = DATE '9999-12-31';
-- 2) 未变化实体:把上一日的当前行延续到今日(通常用 UNION ALL 覆盖写实现)
-- 3) 变化实体:插入新版本,end_date 置为极限日期拉链表字段读法
| 字段 | 含义 | 异常表现 |
|---|---|---|
| start_date | 本版本生效日 | 早于业务首次出现日期说明初始化有误 |
| end_date | 本版本失效日 | 当前版本应为极限日期 |
| end_date 为 NULL | 另一种「当前」表示法 | 与极限日期混用会静默漏行 |
| 区间重叠 | 同一天命中两行 | 查询结果行数翻倍 |
区间统一用左闭右开 [start_date, end_date) 更不容易出错:相邻版本首尾相接,不会出现同一天命中两行。
首次初始化时必须给所有行设置极限 end_date,否则后续关链语句找不到目标行,变更实体上会同时保留多行「当前状态」。
新手最常问的两件事
第一,拉链表能不能改成按天全量快照?能,但存储与计算成本会随天数线性增长,拉链表的价值正是用「只存变化」换空间。第二,按天关联时要不要做去重?只要区间条件正确(左闭右开),同一天不会命中两行,不需要额外去重;反过来,如果查询结果出现重复,第一个该检查的就是区间写法与是否存在多行当前状态。另外要注意删除实体的表示方式:拉链表一般不给物理删除,而是在到期日关闭该行。