Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 数据库设计/延迟/并发,令人头痛_Database_Postgresql_Concurrency_Hierarchical Data_Latency - Fatal编程技术网

Database 数据库设计/延迟/并发,令人头痛

Database 数据库设计/延迟/并发,令人头痛,database,postgresql,concurrency,hierarchical-data,latency,Database,Postgresql,Concurrency,Hierarchical Data,Latency,我有一个客户机-服务器应用程序,它从两个表中获取所有数据,重新计算并存储数据 例如: 每个项目都有一份“材料清单”=其他项目的清单和数量。因此,物料的成本是物料清单中物料的成本*其数量的总和。最终,一些基本项目没有BOM,只是单独设置了成本。ie:原材料 ie:A的BOM表上说它是由2xB和3xC组成的 我现在所做的,我不记得为什么我会这样做,是我从数据库中获取所有项目和所有BOM,然后一次计算每个项目的递归成本。一旦我计算了一个项目,我就标记它,这样我就不会再重做成本了。还可以防止无限递归 问

我有一个客户机-服务器应用程序,它从两个表中获取所有数据,重新计算并存储数据

例如:

每个项目都有一份“材料清单”=其他项目的清单和数量。因此,物料的成本是物料清单中物料的成本*其数量的总和。最终,一些基本项目没有BOM,只是单独设置了成本。ie:原材料

ie:A的BOM表上说它是由2xB和3xC组成的

我现在所做的,我不记得为什么我会这样做,是我从数据库中获取所有项目和所有BOM,然后一次计算每个项目的递归成本。一旦我计算了一个项目,我就标记它,这样我就不会再重做成本了。还可以防止无限递归

问题是,这有点愚蠢:首先,它很慢,会重新计算没有改变的东西,更糟糕的是,给它一个足够大的DB,它就会耗尽内存

相反,我可以根据需要重新计算物料:当物料的BOM发生更改时,我重新计算该BOM,然后选择包含此更新物料的所有BOM,并重新计算它们;冲洗并递归重复“直到到达顶部,DB中的BOM表不依赖于任何更改的项目

这在实践中意味着什么:假设一些项目是原材料,其成本可能会经常更新,而一些项目是最终用户的东西,其BOM即使发生变化也很少会发生变化。当用户更改其中一种材料的成本时,可能意味着要处理成千上万的项目,重新计算它们。假设选择1个项目/BOM需要15秒我在Postgresql上,那么仅选择1000个项目/BOM需要15秒,然后您必须将重新计算的成本更新回数据库中的项目。。。哦,天哪,延迟现在可以变成几分钟了

我工作的公司使用的ERP软件采用了第一种方法:一次批量重新计算整个数据库。这实际上需要几个小时,而且在使用10多年的时间里,这种方法的问题似乎一直在积累。批量重新计算每周进行一次

现在我已经大声地写出来了,我不认为这需要几分钟的时间。问题是我不太了解数据库,我担心并发性:因为更新项目a需要很长时间,所以可能有人会在更新项目a期间更新第二个项目B

假设D项由上面的A和B组成。用户1更新了A,因此服务器软件开始与DB自慰几分钟,最终更新了D。但与此同时,用户2更新了B,因此服务器最终将再次更新D

使用Postgresql的事务可以解决这个问题吗?事务从DB的当前状态开始,因此事务1看到D由A1和B1组成,并将A从A1更新为A2,但在完成并提交之前,事务2将开始,也看到A1和B1。T1重新计算并提交,D=A2+B1。但是T2已经开始了,没有看到新的A,A2。因此,它最终向DB提交D=A1+B2,这是不正确的。它应该是D=A2+B2

此外,一些处理过程会重叠,从而浪费服务器时间

如果我按顺序而不是并行地执行T1和T2,那么万岁,答案是正确的,但是用户2将不得不等待更长的时间。此外,如果一组交易彼此之间没有关系,且完全独立。。。依赖树;ie:A=X+Y和B=N+M,那么并行计算将给出正确的答案,并且对用户来说速度更快

重要提示:即使按顺序处理,我仍然会使用事务,因此软件的其余部分仍然可以并行处理这些数据,但重新计算成本的功能除外

现在,如果……的话,按顺序进行的整个过程就不会那么糟糕了。。。。数据库延迟不会那么糟糕。比如说,如果整个数据都保存在RAM中,那么通过1000个对象将是轻而易举的事。啊,但即使我构建了一个系统来快速地将数据块从磁盘/RAM移动到磁盘/RAM,并进行一些缓存(以替换数据库),这也不行,因为我仍然需要事务,以便服务器的其余功能可以并行工作。”重要提示'以上,所以我会结束建设另一个数据库。可能快一点,但这很愚蠢/浪费时间

我缓存每个项目的成本的全部原因是,我不会每次使用它时都重新计算它,因为它不仅浪费有限的资源,而且数据库延迟太大,并发问题的规模甚至更大

现在我不必奇怪为什么他们要大批量生产。。。这让我头疼

你们如何以最佳方式解决这个问题

根据我目前的理解,也就是说,在面对之前我默默忽略的并发性问题之后,我会让该函数按顺序使用事务,然后 e应用程序的其余部分仍然能够并行使用数据,我相信这对用户来说是最好的。这就是目标:对用户最好,但保证系统的正确性

也许以后我可以用硬件和软件来减少延迟,但现在我开始对自己撒谎了

另外,在过去的几个月里,我对一些非常明显的事情完全视而不见,有些事情与编程无关,所以我希望有人会指出一些我设法错过的非常明显的事情……:|

我不记得我为什么这样做

这件事突然向我袭来,这是你需要解决的第一件事

没有任何理由仅仅为了计算每个BOM的总成本而需要将数据返回到应用程序。在SQL中,有许多技术可以处理部件爆炸或分层数据集

我在演讲中介绍了几种解决方案,你也可以读一本像这样的书

有些解决方案是特定于供应商的,有些可以使用任何普通的SQL DBMS来完成。我没有注意到数据库的品牌,但Jonathan正确地告诉我您正在使用PostgreSQL

在这种情况下,您应该阅读有关WITH查询的内容,这是PostgreSQL 8.4中新增的内容,并允许您执行一些复杂的递归查询效果

我已经实现了一个系统,其中BOM由单个资源的层次结构组成,我不必执行您描述的任何批处理。无可否认,在我处理数据库时,数据库中只有几千个资源

您应该学习如何在SQL中使用聚合函数,如SUM和GROUP,任何关于SQL的书籍都应该包括这一点,以及存储实体层次关系的技术

既然您说您不太了解数据库,我建议您在对实际系统进行任何更改之前尝试实现一个玩具系统。我只是根据个人经验说的,但我发现,当我同时尝试在实际项目中运用新的技术时,我无法学习新的技术技能

我不记得我为什么这样做

这件事突然向我袭来,这是你需要解决的第一件事

没有任何理由仅仅为了计算每个BOM的总成本而需要将数据返回到应用程序。在SQL中,有许多技术可以处理部件爆炸或分层数据集

我在演讲中介绍了几种解决方案,你也可以读一本像这样的书

有些解决方案是特定于供应商的,有些可以使用任何普通的SQL DBMS来完成。我没有注意到数据库的品牌,但Jonathan正确地告诉我您正在使用PostgreSQL

在这种情况下,您应该阅读有关WITH查询的内容,这是PostgreSQL 8.4中新增的内容,并允许您执行一些复杂的递归查询效果

我已经实现了一个系统,其中BOM由单个资源的层次结构组成,我不必执行您描述的任何批处理。无可否认,在我处理数据库时,数据库中只有几千个资源

您应该学习如何在SQL中使用聚合函数,如SUM和GROUP,任何关于SQL的书籍都应该包括这一点,以及存储实体层次关系的技术


既然您说您不太了解数据库,我建议您在对实际系统进行任何更改之前尝试实现一个玩具系统。我只是根据个人经验说的,但我发现,当我同时尝试在实际项目中使用新的技术技能时,我无法学习新的技术技能。

对我来说,这听起来像是一种计算,它将受益于数据库中的存储过程,或多或少与您使用的实现方法无关。这减少了客户机和服务器之间的通信量,这几乎总是会提高这样一组复杂计算的性能

你说:

我现在所做的,我不记得为什么我会这样做,是我从数据库中获取所有项目和所有BOM,然后一次计算每个项目的递归成本。一旦我计算了一个项目,我就标记它,这样我就不会再重做成本了。还可以防止无限递归

我对这个解释中的“标记它”部分感到困惑——不知道你为什么用这种方式做事是个坏消息。你真的需要了解你在做什么

有很多方法可以进行BOM处理,Bill Karwin向您介绍了一些有趣的信息,SQL反模式链接大约有250张幻灯片!。SQL反模式部分讨论了下面概述的“原始树”。但是,这些解决方案不包括下面概述的情况,因为一个子部件可以是多个产品的组件,所以多个父级可以使用同一子树

路径枚举无效:不能使用相同的子部件信息 因为您将包含产品信息的构建到路径中。 在一个产品中使用子部件时,嵌套集工作良好;在许多产品中使用子组件时,情况并非如此。 “封闭表”解决方案可用于解决这一问题——它或多或少是下面的第二个备选方案。 你需要考虑对受影响的部分做一个自下而上的扫描是否有意义,或者是做一个广度优先还是深度优先扫描。此决策的一个驱动因素是BOM数据的性质。如果您有一个结构,其中某个子组件用作多个产品的组件,您是为每个产品分别记录子组件中使用的零件,还是记录产品使用子组件

澄清:

子组件A P001包含24 x 8mm螺母P002、24 x 8mm x 50mm螺栓P003、1 x基板P004、1 x盖板P005。 产品B P006包含1个子组件A和许多其他零件。 产品B P007包含1个子组件B和许多其他零件。 您的BOM记录可能看起来像这棵天真的树:

Part      Component     Quantity
P001      P002          24
P001      P003          24
P001      P004          1
P001      P005          1
P006      P001          1
P007      P001          1
或者它们可能看起来像这个闭合表:

Part      Component     Quantity
P001      P002          24
P001      P003          24
P001      P004          1
P001      P005          1
P006      P002          24
P006      P003          24
P006      P004          1
P006      P005          1
P007      P002          24
P007      P003          24
P007      P004          1
P007      P005          1
第二种情况不太理想-要获得正确的数值要困难得多,如果像螺母或螺栓这样的零件,多个子组件可以使用同一个零件,那么要获得主要可交付产品P006、P007的正确计数将非常困难。然而,在第二种情况下,重新计算任何零件的成本要简单得多-您只需计算构成零件的每个组件的“成本乘以数量”之和。如果您保留naïve树来记录零件结构分解,并在某些产品或子组件的结构(而非价格)发生变化时重新计算闭包表,那么您可能已经接近nirvana了


在某个地方,但在另一台计算机上,我有一些旧代码来处理这些东西,使用虚构的程序集。编码完成了。。。咕哝,咕哝。。。很久以前,使用临时表,没有提到嵌套集或路径枚举;它确实为特定的DBMS计算闭包表——它必须适应其他DBMS。问吧,我会把它挖出来

对我来说,这听起来像是一种计算,它将受益于数据库中的存储过程,或多或少地与您使用的实现方法无关。这减少了客户机和服务器之间的通信量,这几乎总是会提高这样一组复杂计算的性能

你说:

我现在所做的,我不记得为什么我会这样做,是我从数据库中获取所有项目和所有BOM,然后一次计算每个项目的递归成本。一旦我计算了一个项目,我就标记它,这样我就不会再重做成本了。还可以防止无限递归

我对这个解释中的“标记它”部分感到困惑——不知道你为什么用这种方式做事是个坏消息。你真的需要了解你在做什么

有很多方法可以进行BOM处理,Bill Karwin向您介绍了一些有趣的信息,SQL反模式链接大约有250张幻灯片!。SQL反模式部分讨论了下面概述的“原始树”。但是,这些解决方案不包括下面概述的情况,因为一个子部件可以是多个产品的组件,所以多个父级可以使用同一子树

路径枚举不起作用:您不能使用相同的子部件信息,因为您将包含的产品信息构建到路径中。 在一个产品中使用子部件时,嵌套集工作良好;在许多产品中使用子组件时,情况并非如此。 “封闭表”解决方案可用于解决这一问题——它或多或少是下面的第二个备选方案。 你需要考虑对受影响的部分做一个自下而上的扫描是否有意义,或者是做一个广度优先还是深度优先扫描。此决策的一个驱动因素是BOM数据的性质。如果您有一个结构,其中某个子组件用作多个产品的组件,您是为每个产品分别记录子组件中使用的零件,还是记录产品使用子组件

澄清:

子组件A P001包含24 x 8mm螺母P002、24 x 8mm x 50mm螺栓P003、1 x基板P004、1 x盖板P005。 产品B P006包含1个子组件A和许多其他零件。 产品B P007包含1个子组件B和许多其他零件。 您的BOM记录可能看起来像这棵天真的树:

Part      Component     Quantity
P001      P002          24
P001      P003          24
P001      P004          1
P001      P005          1
P006      P001          1
P007      P001          1
或者它们可能看起来像这个闭合表:

Part      Component     Quantity
P001      P002          24
P001      P003          24
P001      P004          1
P001      P005          1
P006      P002          24
P006      P003          24
P006      P004          1
P006      P005          1
P007      P002          24
P007      P003          24
P007      P004          1
P007      P005          1
第二种情况不太理想-要获得正确的值要困难得多,如果像螺母或螺栓这样的零件一样,多个子组件可以使用同一零件,那么就更难获得正确的值 g主要可交付产品P006、P007的正确计数将非常困难。然而,在第二种情况下,重新计算任何零件的成本要简单得多-您只需计算构成零件的每个组件的“成本乘以数量”之和。如果您保留naïve树来记录零件结构分解,并在某些产品或子组件的结构(而非价格)发生变化时重新计算闭包表,那么您可能已经接近nirvana了

在某个地方,但在另一台计算机上,我有一些旧代码来处理这些东西,使用虚构的程序集。编码完成了。。。咕哝,咕哝。。。很久以前,使用临时表,没有提到嵌套集或路径枚举;它确实为特定的DBMS计算闭包表——它必须适应其他DBMS。问吧,我会把它挖出来