如何维护可用于通过关系同时编辑的同一实体的两个版本?

问题

考虑以下数据库表:

  1. 产品
  2. 订购
  3. 订单详细信息
  4. 用户

产品具有以下列:

Product_Name,Product_Description,Product_Size,Product_Cost,Product_Unit 

订单包含以下列:

Order_number,Order_Total,Order_Status,Order_Payment_Status,Order_UserId (Fk of user table),Order_date

“订单详细信息”具有以下列:

OrderDetails_OrderId(Fk of Order table),OrderDetails_ProductId (Fk of Product table),OrderDetails_Quantity

用户具有列:

User_Name,User_Phone (unique),User_Email (unique),User_Address

考虑,要下达,打包,交付,取消,关闭的订单状态。

现在,用户u1有3个订单:

  1. 订单O1->放置状态(可由用户编辑)
  2. 订购O2->放置状态(可由用户编辑)
  3. 订单O3->已关闭状态(用户不可编辑,但可通过管理员编辑

现在的情况是用户u1更新他的信息。更新后的信息应仅在O1和O2中开始反映,因为它们仍处于放置状态;而O3已经为用户关闭,现在仅开放给管理员编辑-因此O3仍应反映以前存在的旧用户信息。使用当前的数据库结构-这是不可能的。

类似地,如果管理员以关闭的顺序编辑那里的产品,则不应以关闭的顺序显示编辑内容。

您可能已经发现,上面描述的当前结构是一个简单的与外键相关的结构,其中一个编辑显然会直接反映所有相关实体。

我想出了什么解决方案?

解决方案1:版本化 切勿更新任何行/条目。始终为任何更改添加新行(软更新)。继续添加带有一些标记/标识/时间戳/审核跟踪(已编辑)的行,并使用映射表将版本与订单表进行映射。

User_Name | User_Phone | User_Email     | User_Address | Version/Timestamp
abc       | 123        | abc@email.com  |someaddres    | v1
abc       | 234        | abc@email.com  |someaddress   | v2

new mapping table
version | order_id 
v1      | o3

此解决方案的缺点

  1. 同一实体的同一表中有多个条目-那么我们将无法使用唯一键。在这里,电话和电子邮件是唯一的,但是如果我们采用这种方法,则必须删除唯一的索引。
  2. 所有具有User表外键的表(与顺序无关)都会产生影响。例如,user_feedback表仅具有用户的外键,但是现在由于有多个条目具有同一用户的不同版本,因此该表将受到不必要的影响。
  3. 当用户数量增加时,某些查询的性能将会受到影响。
  4. 用户的电子邮件是用于登录的身份。在同一张表中无论如何都无法进行复制。

否,这不是审核跟踪! 根据我们的要求,我们要保留给o3的旧信息仍应保持可编辑状态。因此,还必须对这些编辑进行审核。因此,审核跟踪将完全是一个单独的包装器。

解决方案2:订单关闭后,创建一个新表,其中包含保存所有各个表的json / dump的列

new table
order_id | JsonOfUser         | JsonOfProductDetails | ...
o3       | {"name":"abc",...} | ...                  |

此解决方案的缺点

  1. 转储的内容是可编辑的,但是这里转储的数据很难编辑,因为现在表已更改,并且此表具有有效地要进行编辑的string / jsonb列,并且其他导航也已删除(非规范化),因此所有可能由于编辑而发生的计算更改也必须手动完成。
  2. 此表中审核的审核跟踪会很麻烦,因为我们将在此处审核json编辑。
  3. 深层子jsons-增加代码复杂度。

解决方案3:创建结构完整的所有表的副本,这些副本与根据状态事件的顺序相关联

User_Common

User_Closed

对于订单O3,在关闭时,user_common的所有详细信息将被复制到User_closed,具有User_common表的外键的订单O3将被User_Closed表的外键更改。现在,o3中的任何更改都将有效地覆盖旧数据,所有其他未结/下达的订单仍可以从User_common获取更新的信息。

此解决方案的缺点

  1. 假设符合此要求的订单中恰好有10个这样的表,则必须制作每个表的副本
  2. 基于订单的事件/状态,每个实体现在都由两个表有效地表示-可能发生同步问题和数据保存问题-即可维护性。
  3. 此处订购表的外键正在更改。如此有效地在订单表中,将有两个外键列:一列用于user_common,另一列用于user_closed。因此,当订单打开时,user_closed外键将保持为空,而当订单关闭时,它将被填充。在此之前,仍然会发生1种数据操作,一种是将有关订单关闭的信息从user_common表复制到user_closed。
  4. 在代码中,我们总是必须根据订单状态(另一个DB调用)来使数据库检查是否应该在公用表或封闭表中进行查找-导致代码级的认知复杂性

这是对我们的要求和研究中提出的解决方案的最小伪造。在不增加不必要的复杂性的情况下,可以满足此要求的实际可行设计是什么?

iCMS 回答:如何维护可用于通过关系同时编辑的同一实体的两个版本?

使用具有 User 表的方法,为 valid_since 列添加另一列。将“禁止删除”策略应用于用户

如果衡量性能问题,请为用户添加一个固定/物化(在内存中)视图,该视图仅显示最新地址-使用该视图获取新下订单的user_id并加入以显示订单那是开放的。对于使用外键进入 User 的现有订单的联接,大多数情况下并不关心实际的 user_id 到底有多少(简化)。 / p>

用户上使用 after_insert 触发器将新的 user_id 传播到表中 Order 的所有条目应该反映出这些更改,请忽略该更新的已关闭订单。就订单而言,这将是一个相当小的更新-允许一个用户拥有多少个未结订单? 10个? 20吗50?

定期清理用户数据,以防它们发生更改但从不订购任何内容-这些 User 条目会被删除。

您可以通过这种方式确保数据库级别的完整性-如果您要为用户添加报告,这些用户如果要更改其详细信息,则每天要进行三次(或明智地限制这些更改)。


您的大多数用户字段也应该是1:N关系-我至少有3个电话号码,并且可能使用2个地址(居住和运输),并且给出的电子邮件数超过1个。

使用“活动”将它们扩展到自己的表中可能会消除创建完整用户副本的需要。基于商务需求,可能需要记住用于运送物品的“地址”,而不是用于订购的手机号码或用于向其发送确认的电子邮件,但这只是一个商业决定。

除非您拥有一家非常活跃的商店,其中有数百万个不同的用户,每个用户订购数百个订单,并且每个月要更改二十次详细信息,否则您在使用当前最先进的数据库系统时都不会遇到问题。在我看来,这是一个基于实际需求的思想实验?

本文链接:https://www.f2er.com/1503824.html

大家都在问