源系统主键会复用,数仓怎么建模?删掉再建还是同一个对象吗?
面试怎么回答
我会先确认主键在系统、租户和生命周期里的唯一范围。若存在删除后复用,需要可靠的实体代次或来源标识,为不同实体分配不同数仓身份,并把事实绑定到正确代次。变更处理除了ID,还要校验代次和源端顺序,防止旧删除覆盖新对象。无法辨别时应隔离待确认,而不是仅凭到达时间猜测。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
昨天编号42是一家门店,今天这家门店已经关闭,编号42却被分配给了另一家。数仓如果只按ID关联,昨天的营业额会不会突然记到新店头上?
主键只在约定的范围和生命周期内唯一;出现复用时,要把实体代次与历史事实绑定,防止新旧对象串联。
数据库唯一,不代表跨历史唯一
数据库主键约束通常约束当前表里的行。旧记录删除之后,相同值能否再次出现,取决于源系统设计。外部编号重新分配、租户独立编号、测试数据转正式数据,都可能让“看上去全局唯一”的字段失去这个前提。
因此建模第一步不是马上生成一个代理键,而是明确自然键的有效范围:哪个系统、哪个租户、哪一种对象,以及是否跨生命周期保持唯一。
如果源系统承诺不可复用,也要把承诺落实为数据契约和监控。只看目前样本没有重复,不能证明未来迁移和恢复不会产生复用。
给每一代实体独立的身份
理想输入包含不可复用的实体标识,或者可靠的创建代次。数仓可以基于来源系统、租户、业务ID和代次,分配稳定的实体代理键。
要区分“同一家门店改名”与“原门店销户,另一个实体用了旧编号”。前者通常属于同一实体的属性变化,后者则需要新的实体身份。不能把所有属性变化都生成新实体,也不能把所有同号记录都合成一条。
创建时间有时能帮助判断,但不是天然可靠的代次字段。历史导入可能重写创建时间,秒级时间也可能冲突。应先核实生成规则和精度,必要时要求上游提供不可变标识。

事实为什么也要记录这个边界?
维表能区分两代对象,事实却只留下业务ID,仍然可能串联。关联时需要找到事件发生时所属的实体代次,或者直接在采集与明细加工时保留该身份。
如果只有业务时间,也要确认代次有效区间不重叠、边界明确,并处理迟到事件。源端历史缺失、时钟异常和迁移批次可能让时间判断不足,此时应标记无法归属,而不是强行分配到最新一代。
已经发布的历史事实,还要避免随着维表当前行变化而漂移。代理键是保存关联结果的工具,不会自动证明第一次关联就是正确的。
旧删除到达得晚,不能删除新实体
假设旧对象的删除事件延迟到达,而新对象已经入仓。若下游执行“按ID删除”,新一代也可能被一并移除。
应用变更时,应校验事件属于哪个实体代次,并使用来源端可解释的版本或顺序约束。接收时间只能说明什么时候到达,不等于业务变更发生的先后。
没有代次字段时,可以结合可靠日志顺序、完整创建删除链和恢复边界推断,但推断必须可验证。跨源顺序不能强行比较;缺失关键事件时,暂停受影响键的自动处理比静默串数据更容易恢复。
一个典型场景:老店收入跑到了新店
比如一个门店系统在迁移后重新使用旧编号。报表发现新店开业前就有营业额,最初判断是订单日期错误,于是检查了时区和日期转换。
真正的问题是订单按业务ID关联到了当前门店。旧验收只核对订单金额总和、关联非空率与当前维表唯一性,这些指标全部正常:金额没有变,只是归属错了。
修正需要重建实体代次映射,按历史证据回填受影响订单,并把不确定归属单独列出。新增验收则检查“实体创建前的异常事实”、同号多代和迟到删除,不再只盯总额。
这个问题也提示我们,代理键并不是按行生成一个数字就完成建模。它必须对应稳定的业务身份规则,并允许解释某条事实为何属于这一代对象。
先阻止错误扩散,再补足历史
发现复用后,先确认影响的是单租户、单系统还是公共维度,列出消费该身份的事实和标签。不要立即全表重映射,否则未确认的推断会一次性污染更多下游。
对已经确认的范围分批回填,对证据缺失的部分保留原值、疑点与处理状态。等上游补充创建记录或迁移映射后再修正,才有一条能审计、能回退的治理路径。