首页/数据/数仓建模速查/当前标志与最新版本定位
维度与事实设计149 条

当前标志与最新版本定位

用 is_current 或远期 end_date 标识当前行;查询最新维度先过滤当前标志,避免按自然键 group by 取版本号最新行的昂贵写法。

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

当前标志是什么

在拉链维表里定位「最新版本」有两种做法:维护 is_current 标志(0/1),或者用远期 end_date(如 9999-12-31)表示当前行。查询最新属性时直接过滤当前标志,可以避免按自然键取版本号最大行那种昂贵写法。约束是每个自然键至多一条 is_current=1,且关闭旧行与插入新行必须在同一批次完成,否则会出现零条或两条当前行。

基本信息

标志列is_current 或 cur_flag,取值 0/1
硬约束每个自然键恰好一条当前行
校验频率每日调度后自动跑唯一性检查
配套列start_dt / end_dt 表示版本生效区间
更新要求关闭旧行与插入新行在同一事务或同一批次完成

典型使用场景

  • 事实加载:解析维度代理键时用 is_current=1 定位当前版本
  • 报表查询:取最新属性先过滤当前标志,避免窗口函数排序
  • 数据质量巡检:每日校验每个自然键的当前行是否恰好一条
  • 更新优化:仅重写当前行所在分区,降低原地更新代价
  • 版本关闭:更新旧行必须带 is_current=1 条件,防止改写历史行
  • 异常定位:出现零条当前行说明关闭成功但插入失败,两条则相反

当前行唯一性校验

当前行唯一性校验
-- 查多行:同一自然键出现多条当前行
SELECT user_id, count(1) AS cnt
FROM   dim_user
WHERE  is_current = 1
GROUP  BY user_id
HAVING count(1) > 1;

-- 查零行:自然键在维表里存在但没有任何当前行
SELECT h.user_id
FROM   dim_user h
GROUP  BY h.user_id
HAVING sum(case when h.is_current = 1 then 1 else 0 end) = 0;

-- 取最新属性:直接过滤当前标志,不要按版本号排序
SELECT user_id, name, tier FROM dim_user
WHERE  user_id = 'U10086' AND is_current = 1;

两种当前行标识

方案优点注意点
is_current 标志查询简单,可直接过滤必须有唯一性约束;更新要带条件防改写历史
远期 end_date无需额外列,区间语义自然可读性差;按 end_date 筛选易写错,需固定常量
两者并用查询方便且区间完整两列必须同时维护,任一漏改即不一致
版本号取最大无需额外列需窗口函数排序,大表代价高
用 is_current 时切忌写成「先插新行再关旧行」却不加条件:关闭旧行时若漏了 is_current=1,会把该自然键的全部历史行一起关掉,历史版本的有效期被整体改写,这类事故往往几天后才被发现。

易错点

  • 关闭旧行与插入新行分离且无事务保护:失败后同一自然键出现两条当前行,报表重复计数
  • 关旧行漏写 is_current=1 条件:全历史行被一起关闭,有效期信息整体损毁
  • 只靠 end_date 判当前且留 NULL:筛选与索引都失效,还容易与远期值混用
  • 不跑唯一性校验:多当前行与零当前行长期潜伏,直到对账才发现
  • 当前标志混入变更检测:把它算进哈希,每批数据都被判为变更,拉链失控

数据来源与参考

  • 拉链表实现实践
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌