库存数据库设计

81

这不是一个关于“编程”的问题(不针对任何语言或数据库),而更多的是设计和架构方面的问题。也是一种类型为“如何以最佳方式做X”的问题。我希望这不会引起太多的“宗教”争论。

在过去,我开发了一些系统,以某种方式保留物品(不是相关的物品)的库存清单。其中一些使用不支持事务的语言/数据库。在这种情况下,我选择不在物品记录的字段中保存物品的手头数量。相反,手头数量是通过计算总收到的库存-出售的库存总数来计算的。这几乎没有因软件而导致库存差异。表格已正确索引,性能良好。有一个归档流程,以防记录数量开始影响性能。

现在,几年前我开始在这家公司工作,并继承了一个跟踪库存的系统。但数量是保存在字段中的。当注册一个条目时,收到的数量被添加到项目的数量字段中。当出售一个物品时,数量被减少。这导致了差异。在我看来,这不是正确的方法,但这里的之前的程序员坚称这是正确的方法。

我想知道是否有共识关于设计这样的系统的正确方法。还有什么资源可用,印刷或在线,以寻求此方面的指导。

谢谢


18
当你说“这里之前的程序员都对它很信任”时,你是指他们每次工作时都会发誓吗? - MusiGenesis
12个回答

57

我在我的公司看到过这两种方法,肯定更倾向于第一种方法(根据库存交易计算总数)。

如果您只是在某个字段中存储总数量,那么您不知道如何得出该数字。 没有事务历史记录,您可能会遇到问题。

我编写的最后一个系统通过将每个交易作为带有正负数量的记录存储来跟踪股票。 我发现它非常有效。


1
+1 我曾经也有同样的困惑,现在我认为这是最好的选择。 - INS
4
你能否评论一下这种方法的性能?看起来这是受欢迎的方法,但如果你有数百种产品和数千个交易,那么何时或如何计算累积总额呢?或者你只是将累积总额存储在另一个地方,并放心知道如果需要的话可以重新计算吗? - Simon_Weaver
12
我进行了一个测试——发布了大约3百万条正负库存调整记录,涉及2000个产品。按SKU分组对所有行的加总只需要不到一秒钟的时间。我必须说,我对它的快速运作感到非常惊讶。就我正在进行的项目而言,我确实还有数倍于此的增长空间,短时间内不用担心这个问题。显然,如果您要在网站上显示实时库存总量,那么您可能希望将其缓存,但即使跨足2000个产品,我也能够几乎瞬间计算出总和。 - Simon_Weaver
3
银行/会计系统通过交易(借方或贷方)进行类似的操作,通常作为单独的字段,但具有相同的总和效果。主要出于运营原因,每月都会创建一个余额(通常还有一个验证月末的过程),但这也是一种方法,可以将12个月的增量数字相加,以便快速地添加一年的总数,而无需每笔交易都计算。在跨越多年和数百万账户时,性能优势是真实存在的,并且允许对几个月前的更正仅需要重新计算该月的结算。 - ClearCrescendo
1
你应该同时应用1个字段作为数量,以及1个表格作为交易记录。数量字段可以在需要时重新计算。由于性能原因,你需要这个字段。当月底到来时,我们应该将上个月的所有数字移动到新的月份。这是我的ERP系统运作方式,并且运作良好。 - Wolf
显示剩余2条评论

21

为了立即帮助读者(并避免链接失效),我们更喜欢提供至少直接概述解决方案的答案,使用链接提供额外信息。 - buncis

9

这要看情况,库存系统不仅仅是为了数物品。例如,为了会计目的,您可能需要根据FIFO(先进先出)模型知道库存的会计价值。这不能通过简单的“总库存收到量 - 总库存售出量”的公式来计算。但是,他们的模型可能会轻松地计算这个值,因为他们在进行操作时修改了会计价值。我不想深入讨论,因为这不是编程问题,但如果他们坚持这个模型,也许您没有完全理解他们需要适应的所有要求。


7

根据情况不同,两种方法都是有效的。当以下条件满足时,前一种方法最好:

  • 要求求和的项目数量相对较小
  • 几乎没有需要考虑的异常情况(返回、调整等)
  • 库存物品数量不是经常需要的

另一方面,如果您有大量的项目、几个特殊情况和频繁访问,则维护物品数量将更加高效。

此外,请注意,如果您的系统存在差异,则它存在错误,应该追踪并消除这些错误。

我已经使用过这两种方法,这两种方法都可以正常工作——只要您不忽略错误!


1
嗯,返回值并不是非常特殊,除非你正在销售纯易腐物品或其他无法再次销售的物品。 - Simon_Weaver
2
@Simon:我早期写过一个定制的冰淇淋店库存系统。退货不仅非常少,而且实际上是不可能的;-) - Steven A. Lowe

4
考虑现有系统以及更改它的成本和风险非常重要。我使用一个类似于您的库存数据库的数据库,但是它包括审计周期并储存调整,就像收据一样。看起来它运作良好,但是所有涉及其中的人都经过了很好的培训,仓库工作人员不太容易学习新程序。
在您的情况下,如果您想要更多跟踪而不改变整个数据库结构,那么我建议添加一个跟踪表(类似于您的“交易”解决方案),然后记录库存水平的更改。 更新大多数库存水平的更改,以便它们也留下交易记录,应该不太难。 您还可以添加定期任务,每隔几个小时将库存水平备份到交易表中,以便即使您错过了某个交易,也可以发现更改发生的时间或回滚到先前的状态。
如果您想看看大型应用程序如何处理,请查看SugarCRM,他们有一个库存管理模块,尽管我不确定它如何存储数据。

4
我认为这实际上是一个关于在每次需要总数时进行(相对)昂贵的计数与每次更改时进行计数并将计数存储在字段中,然后在需要总数时读取该字段的一般最佳实践问题。
如果我不能使用事务,则在每次需要总数时进行实时计数。如果可以使用事务,那么执行库存更新操作和重新计算总数的保存在同一事务中是安全的,这将确保计数的准确性(尽管我不确定这是否适用于多个用户同时访问数据库)。
但是,如果性能不是真正的巨大问题(现代数据库在计算行方面足够好,以至于我很少担心这个问题),我会坚持每次实时计数。

3
我会选择第一种方式,其中库存数量是通过计算总收到的库存减去已售出的库存来确定的。在我看来这是正确的方法。
编辑:我还希望将任何库存损失/损坏因素考虑在内,但我相信您已经覆盖了这一点。

2
Django-inventory 更适用于固定资产,但可能会给你一些启示。例如:ItemTemplate(类) -> ItemsOnHand(实例)。ItemsOnHand可以与更多的ItemTemplates相关联;例如打印机和它需要的墨盒。这还允许为每个ItemsOnHand设置重新订购点。每个ItemsOnHand都链接到InventoryTransactions,这使得审计变得容易。为了避免从成千上万的库存交易中计算实际在手物品,使用检查点,它只是一个余额+日期。要计算在手物品,请查询最近的检查点并开始添加或减去物品以找到当前物品的余额。定期定义新的检查点。

2

我之前曾经处理过解决这个问题的系统。我认为最理想的解决方案是使用预计算列,它可以让你兼顾两者的优点。总计字段会在某个地方,因此不需要昂贵的查找,但它无法与其余数据不同步(数据库会维护完整性)。我不记得哪些关系型数据库支持预计算列,但如果没有事务,可能也不可用。

你可以潜在地使用触发器来模拟预计算列(非常有效...我看不到任何缺点)。不过,你可能需要事务。我认为,在进行这种受控去规范化时保持数据完整性是触发器唯一合法的用途。


1

我可以看到使用两列的一些好处,但是我不明白关于差异的部分 - 你似乎在暗示拥有两列(输入和输出)比单列(当前)更不容易出现差异。为什么呢?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接