库存数仓怎么建模?流水和快照为什么经常对不上?
面试怎么回答
库存模型我会拆成变动流水和周期快照。先固定仓库、货主、SKU、状态及单位,再用期初加区间净变动等于期末做勾稽。关键是把调拨在途、盘点调整、冲正和迟到补数纳入同一时间口径。发现差异后从仓库日期下钻到明细事件,保留快照修订版本,而不是直接把余额改平。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
业务要同时看“今天还剩多少货”和“这些货为什么变多或变少”。只建一张库存快照,可以回答第一个问题;只汇总出入库流水,又可能解释不了期初余额。库存模型需要把状态和变化接起来。
用流水记录变化、快照记录时点状态;统一库存范围、时间口径和计量单位后,再验证期初加净变动等于期末。
粒度要先于“库存数量”这个字段
一行库存可能是仓库加 SKU,也可能还要区分货主、批次、库位和良品状态。如果上游按批次记录,下游只保留 SKU,就要明确哪些属性可以汇总、哪些必须保留。不同租户的同名商品,也不能默认是同一个库存实体。
数量还要有单位。箱和件不能直接相加,转换关系可能因包装版本而变化。实物库存、可用库存、锁定库存也不是同一个指标:锁库不一定减少仓内实物,出库才会改变相应实物状态。先把每类业务动作影响哪些数量写成映射表。
流水解释变化,快照保留状态
流水事实表按一次库存变动明细建模,保留源事件标识、业务单据、变动方向、数量、业务生效时间和入仓时间。冲正应能追溯原流水,不宜直接删除旧记录后假装没有发生过。
日快照按确定的业务日结束时点记录库存余额,方便查存量与库存天数。库存数量通常不能直接跨日期相加;需要平均库存时,也要明确是每日时点均值还是按时间加权,而不是把所有日期余额当成累计销量。
没有发生流水但仍有库存的商品,仍可能需要出现在快照里。若模型只从当天流水生成商品集合,静止库存会消失。快照覆盖范围应来自有效库存实体及期初状态,而不只是当日活跃记录。
对账等式必须在同一范围内成立
在同一库存粒度、相同单位和相同时间边界下,可以检查:期末余额 = 期初余额 + 区间内全部有符号净变动。盘盈盘亏、报损、调拨和冲正都需要按语义进入净变动,不能只算采购入库和销售出库。
假设期初 100 件、入库 20 件、出库 15 件、盘亏 2 件,期末应为 103 件。这只是说明守恒关系的示例,不是任何企业的真实数据。如果快照为 105,先查盘点调整是否遗漏,再查时间和单位,不要直接把差额填进“其他”。

一个典型场景:调拨完成,两个仓都不对
比如仓 A 晚上发出货物,仓 B 次日才验收入库。开发把调拨单状态更新当成两个仓同时增减,看到当晚仓库快照对不上,就怀疑同步少了一批数据。
实际问题可能是忽略了在途库存:发出和收到是两个不同事件,不一定在同一业务日。只看调拨单最终状态无法还原中间状态。模型应分别记录调出、在途和调入,企业总量与单仓余额也应使用各自清晰的统计范围。
原先的检查只比较调拨单数,既没有检查事件阶段,也没有检查两个仓的业务生效时间。修正后按调拨明细追踪两端事件和在途余额,差异才能被解释,而不是靠第二天自然对平掩盖问题。
迟到和盘点,要留出修订机制
业务发生在昨天、今天才入仓的流水,可能要求重算昨天期末和后续滚动余额。应区分暂估快照与已核定快照,记录修订版本和差异来源。只改昨日一张表,却不调整继承该余额的后续日期,会让错误继续传递。
对账可先按日期和仓库缩小范围,再下钻 SKU、批次和事件标识;同时输出源端缺失、重复入仓、口径排除和单位不一致等差异类型。对同一次同步延迟与真正业务异常采用不同处理路径,避免每次都触发人工盘库。