gpt4 book ai didi

database - 如何维护可与关系同时编辑的同一实体的两个版本?

转载 作者:行者123 更新时间:2023-12-04 08:51:46 25 4
gpt4 key购买 nike

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

9 个月前关闭。




Improve this question




问题
考虑这些数据库表:

  • 产品
  • 订购
  • 订单详情
  • 用户

  • 产品有栏目:
    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 有三个命令:
  • 订单 O1 -> 放置状态(可由用户编辑)
  • 订单 O2 -> 放置状态(可由用户编辑)
  • 订单 O3 -> 关闭状态(用户不可编辑, 但管理员可编辑 )

  • 现在的场景是用户 u1 更新他的信息。这个更新的信息应该开始反射(reflect)在 O1 和 O2 中,因为它们仍然处于放置状态;而 O3 已经对用户关闭,现在仅对管理员的编辑开放 - 因此 O3 仍应反射(reflect)以前存在的旧用户信息。使用当前的数据库结构 - 这是不可能的。
    类似地,如果管理员编辑了已关闭订单中的产品,则不应以已关闭订单显示编辑内容。
    您可能已经发现,上面描述的当前结构是一个简单的外键相关结构,其中编辑显然会直接反射(reflect)到所有相关实体。
    我想出了哪些解决方案?
    解决方案 1:版本控制
    永远不要更新任何行/条目。始终为任何更改添加新行(软更新)。继续添加带有一些标签/id/时间戳/审计跟踪(谁编辑)的行,并使用映射表将版本与订单表映射。
    IE。
    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

    此解决方案的缺点是 :
  • 同一个表中有多个条目,对于同一个实体 - 那么我们将无法使用唯一键。在这里,电话和电子邮件是唯一的,但如果我们选择这种方法,则必须删除唯一索引。
  • 所有具有用户表外键的表(与订单无关)都会产生影响。例如user_feedback表只有用户的外键,但是现在由于同一个用户的不同版本有多个条目,这个表将受到不必要的影响。
  • 当用户数量增加时,选择查询的性能将受到影响。
  • 用户的电子邮件是身份,用于登录。无论如何,在同一个表中不可能重复。

  • 不,这不是审计跟踪!
    根据我们的要求,我们要为 o3 保留的旧信息仍应保持可编辑状态。因此,这些编辑也必须经过审计。所以审计跟踪将是一个单独的包装器。
    解决方案 2:当订单关闭时,创建一个新表,其中包含保存所有相应表的 json/dump 的列
    IE。
    new table
    order_id | JsonOfUser | JsonOfProductDetails | ...
    o3 | {"name":"abc",...} | ... |
    此解决方案的缺点 :
  • 转储的东西是可编辑的,但这里转储的数据很难编辑,因为现在表已经改变了,这个表有一个字符串/jsonb 列,可以有效地进行编辑,其他导航被删除(非规范化)所以由于编辑而可能发生的所有计算更改也必须手动完成。
  • 审核此表中编辑的跟踪会很麻烦,因为我们将在此处审核 json 编辑。
  • 深层子 jsons - 增加代码复杂性。

  • 解决方案3:创建结构完整的所有表的副本,根据状态事件与订单相关
    IE。
    User_Common

    User_Closed
    对于订单O3,在关闭时,user_common 的所有详细信息将被复制到User_closed 中,并且具有User_common 表外键的订单O3 将更改为User_Closed 表的外键。现在 o3 中的任何更改都将有效地覆盖旧数据,并且所有其他未结/已下订单仍然可以从 User_common 获取更新信息。
    此解决方案的缺点 :
  • 假设恰好有 10 个这样的表与具有此要求的订单相关,则必须制作每个表的副本
  • 现在,每个实体都由基于订单事件/状态的两个表有效表示 - 可能会发生同步问题和数据保存问题 - 即可维护性。
  • 订单表的外键在这里发生了变化。如此有效地在订单表中,将有两个外键列:一个用于 user_common,另一个用于 user_closed。所以当订单打开时, user_closed 外键将保持为空,当订单关闭时,它将被填充。在此之前,还会进行1次数据操作,1次将user_common表中的订单关闭信息复制到user_closed。
  • 在代码中,我们总是必须根据订单状态(另一个 DB 调用)对数据库检查是否应该在公共(public)表或封闭表中进行查找 - 导致代码级认知复杂性

  • 这是对我们的要求和在研究中提出的解决方案的最小模拟复制 .在不增加不必要的复杂性的情况下,可以遵守此要求的实际可行设计是什么?

    最佳答案

    使用具有 的方法用户 table 为 valid_since 列添加另一列。将“永不删除”策略应用于 用户 s。
    如果您测量性能问题,请为 添加持久化/物化(内存中) View 。用户 只显示最新地址 - 使用它来获取新下订单的 user_id 并加入以显示打开的订单。将使用外键的现有订单连接到 用户 大多不关心实际的 user_id 有多少(简化)。
    上使用 after_insert 触发器用户 将新的 user_id 传播到 的所有条目订购 应反射(reflect)这些更改的表,忽略该更新的已关闭订单。就订单而言,这将是一个相当小的更新 - 允许一个用户拥有多少个未结订单? 10? 20? 50?
    定期清理用户数据,以防他们更改但从不订购任何东西 - 那些 用户 条目可能会被删除。
    您可以通过这种方式确保数据库级别的完整性 - 如果您想为每天更改其详细信息超过三次的用户添加报告(或限制这些更改前端明智)。

    您的大多数用户字段也应该是 1:N 关系 - 我至少有 3 个电话号码,并且可能使用 2 个地址(居住地址 + 送货地址),并且给定了 1 封电子邮件。
    将这些更改为拥有“事件”的表可能会消除创建完整用户副本的需要。基于业务需要,用于运送物品的“地址”可能值得记住,而不是用于订购的手机号码或用于发送确认的电子邮件,但这是一个商业决策。
    除非您有一个非常活跃的商店,拥有数百万个不同的用户,每个用户订购数百个订单并且每个月更改他们的详细信息 20 次,否则您在使用当前最先进的数据库系统时不会遇到任何问题。在我看来,这更像是一个基于实际需求的思想实验?

    关于database - 如何维护可与关系同时编辑的同一实体的两个版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64065166/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com