订阅更新

源系统主键会复用,数仓怎么建模?删掉再建还是同一个对象吗?

面试问 313 约 3 分钟读完

本文目录
  1. 面试怎么回答
  2. 数据库唯一,不代表跨历史唯一
  3. 给每一代实体独立的身份
  4. 事实为什么也要记录这个边界?
  5. 旧删除到达得晚,不能删除新实体
  6. 一个典型场景:老店收入跑到了新店
  7. 先阻止错误扩散,再补足历史

面试怎么回答

我会先确认主键在系统、租户和生命周期里的唯一范围。若存在删除后复用,需要可靠的实体代次或来源标识,为不同实体分配不同数仓身份,并把事实绑定到正确代次。变更处理除了ID,还要校验代次和源端顺序,防止旧删除覆盖新对象。无法辨别时应隔离待确认,而不是仅凭到达时间猜测。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

昨天编号42是一家门店,今天这家门店已经关闭,编号42却被分配给了另一家。数仓如果只按ID关联,昨天的营业额会不会突然记到新店头上?

主键只在约定的范围和生命周期内唯一;出现复用时,要把实体代次与历史事实绑定,防止新旧对象串联。

数据库唯一,不代表跨历史唯一

数据库主键约束通常约束当前表里的行。旧记录删除之后,相同值能否再次出现,取决于源系统设计。外部编号重新分配、租户独立编号、测试数据转正式数据,都可能让“看上去全局唯一”的字段失去这个前提。

因此建模第一步不是马上生成一个代理键,而是明确自然键的有效范围:哪个系统、哪个租户、哪一种对象,以及是否跨生命周期保持唯一。

如果源系统承诺不可复用,也要把承诺落实为数据契约和监控。只看目前样本没有重复,不能证明未来迁移和恢复不会产生复用。

给每一代实体独立的身份

理想输入包含不可复用的实体标识,或者可靠的创建代次。数仓可以基于来源系统、租户、业务ID和代次,分配稳定的实体代理键。

要区分“同一家门店改名”与“原门店销户,另一个实体用了旧编号”。前者通常属于同一实体的属性变化,后者则需要新的实体身份。不能把所有属性变化都生成新实体,也不能把所有同号记录都合成一条。

创建时间有时能帮助判断,但不是天然可靠的代次字段。历史导入可能重写创建时间,秒级时间也可能冲突。应先核实生成规则和精度,必要时要求上游提供不可变标识。

同一个业务ID,也可能对应两个实体

事实为什么也要记录这个边界?

维表能区分两代对象,事实却只留下业务ID,仍然可能串联。关联时需要找到事件发生时所属的实体代次,或者直接在采集与明细加工时保留该身份。

如果只有业务时间,也要确认代次有效区间不重叠、边界明确,并处理迟到事件。源端历史缺失、时钟异常和迁移批次可能让时间判断不足,此时应标记无法归属,而不是强行分配到最新一代。

已经发布的历史事实,还要避免随着维表当前行变化而漂移。代理键是保存关联结果的工具,不会自动证明第一次关联就是正确的。

旧删除到达得晚,不能删除新实体

假设旧对象的删除事件延迟到达,而新对象已经入仓。若下游执行“按ID删除”,新一代也可能被一并移除。

应用变更时,应校验事件属于哪个实体代次,并使用来源端可解释的版本或顺序约束。接收时间只能说明什么时候到达,不等于业务变更发生的先后。

没有代次字段时,可以结合可靠日志顺序、完整创建删除链和恢复边界推断,但推断必须可验证。跨源顺序不能强行比较;缺失关键事件时,暂停受影响键的自动处理比静默串数据更容易恢复。

一个典型场景:老店收入跑到了新店

比如一个门店系统在迁移后重新使用旧编号。报表发现新店开业前就有营业额,最初判断是订单日期错误,于是检查了时区和日期转换。

真正的问题是订单按业务ID关联到了当前门店。旧验收只核对订单金额总和、关联非空率与当前维表唯一性,这些指标全部正常:金额没有变,只是归属错了。

修正需要重建实体代次映射,按历史证据回填受影响订单,并把不确定归属单独列出。新增验收则检查“实体创建前的异常事实”、同号多代和迟到删除,不再只盯总额。

这个问题也提示我们,代理键并不是按行生成一个数字就完成建模。它必须对应稳定的业务身份规则,并允许解释某条事实为何属于这一代对象。

先阻止错误扩散,再补足历史

发现复用后,先确认影响的是单租户、单系统还是公共维度,列出消费该身份的事实和标签。不要立即全表重映射,否则未确认的推断会一次性污染更多下游。

对已经确认的范围分批回填,对证据缺失的部分保留原值、疑点与处理状态。等上游补充创建记录或迁移映射后再修正,才有一条能审计、能回退的治理路径。

刷题进度保存在当前浏览器