Architecture 设计辩论:存储和操作版本化对象的好方法是什么?

Architecture 设计辩论:存储和操作版本化对象的好方法是什么?,architecture,time,rdbms,versions,Architecture,Time,Rdbms,Versions,一开始,我故意把这一点说得含糊不清。我在寻找讨论,什么问题比我寻找的答案更重要 我正在设计一个应用程序,比如投资组合管理。到目前为止,我的设计是 问题:需要解决的问题 解决方案:一个或多个问题的建议解决方案 关系:两个问题、两个解决方案或一个问题和一个解决方案之间的关系。进一步细分为: 父子-某种分类/树层次结构 重叠-两个解决方案或两个问题真正解决同一概念的程度 地址-问题解决方案的程度 我的问题是关于这些事物的时间性。问题突然出现,然后消失。解决方案有一个预期的解决日期,但在开发过程

一开始,我故意把这一点说得含糊不清。我在寻找讨论,什么问题比我寻找的答案更重要

我正在设计一个应用程序,比如投资组合管理。到目前为止,我的设计是

  • 问题:需要解决的问题
  • 解决方案:一个或多个问题的建议解决方案
  • 关系:两个问题、两个解决方案或一个问题和一个解决方案之间的关系。进一步细分为:
    • 父子-某种分类/树层次结构
    • 重叠-两个解决方案或两个问题真正解决同一概念的程度
    • 地址-问题解决方案的程度
我的问题是关于这些事物的时间性。问题突然出现,然后消失。解决方案有一个预期的解决日期,但在开发过程中可能会进行修改。随着问题和解决方案的发展,关系的程度可能会随着时间的推移而变化

那么,问题是:什么是对这些东西进行版本控制的最佳设计,这样我就可以从当前和历史的角度来看待我的投资组合

后来:也许我应该把这个问题说得更具体些,尽管@Eric Beard的答案值得一提

我考虑过三种数据库设计。我将对每一个都做足够的说明,以显示它们的缺点。我的问题是:选择哪个,或者你能想出更好的吗

1:问题(以及单独的解决方案)在版本控制中是自参考的。 这是有问题的,因为每次我想要一个新版本时,我都必须复制整行,包括长
描述

2:创建新关系类型:版本。 这只是将关系从问题和解决方案表移动到关系表中。同样的复制问题,但可能有点“干净”,因为我已经有了一个抽象的关系概念

3:使用更像Subversion的结构;将所有问题和解决方案属性移动到单独的表中,并对其进行版本设置。 这意味着要加载问题或解决方案的当前版本,我必须获取属性的所有版本,按日期排序,然后使用最新版本。这可能并不可怕。对我来说真正糟糕的是,我不能在数据库中键入检查这些属性。
value
列必须是自由文本。我可以将
name
列作为一个单独的
attribute\u names
表的引用,该表有一个
type
列,但这并不强制在
attributes
表中输入正确的类型

稍后:回应@Eric Beard关于多表外键的评论:


唉,我所描述的太简单了:只有两种类型(问题和解决方案)。实际上我有9到10种不同类型的东西,所以在你的策略下我会有9到10列外键。我想使用单表继承,但它们的共同点太少,因此将它们合并到一个表中是非常浪费的。

嗯,听起来有点像这个网站

就数据库设计而言,像SVN这样的版本控制系统可能是您所需要的,在这种系统中,您实际上从不进行任何更新,只是在事情发生变化时插入(带有版本号)。这称为MVCC,多值并发控制。wiki是另一个很好的例子。

@Gaius

foreign key (thing_id, thing_type) -> problems.id or solutions.id
使用这些“多向”外键时要小心。我的经验表明,当连接条件必须在确定要连接哪个表之前检查类型时,查询性能会受到极大的影响。它看起来不那么优雅,但可以为空

problem_id and solution_id 
这样会更好

当然,当您必须添加检查以获取记录的最新版本时,MVCC设计也会影响查询性能。折衷的办法是,您永远不必担心与更新的争用。

我想可能会有

备选方案4:混合动力 将公共事物属性移动到单个继承表中,然后添加一个
custom\u attributes
表。这使得外键更简单,减少了重复,并允许灵活性。它不能解决附加属性的类型安全问题。它还增加了一点复杂性,因为现在有两种方式可以让一个事物拥有属性

如果
description
和其他大字段保留在Things表中,那么它也不能解决复制空间问题

table things
  int id | int type | string name | text description | datetime created_at | other common fields...
  foreign key type -> thing_types.id

table custom_attributes
  int id | int thing_id | string name | string value
  foreign key thing_id -> things.id

您对此有何看法:

表格问题
int id |字符串名称|文本描述|创建日期时间|

表问题\u修订版
int revision | int id | string name | text description | datetime created _at
外键id->problems.id

更新之前,您必须在修订表中执行额外的插入。这个额外的插入很快,但是,这是你必须支付的

  • 高效访问当前版本-按常规选择问题
  • 直观且接近您想要建模的现实的模式
  • 模式中的表之间的联接保持高效
  • 使用每个业务事务的修订号,您可以对表记录进行版本控制,就像SVN对文件进行版本控制一样

  • 最好选择一种数据结构,使您对模型提出的常见问题易于回答。你很可能大部分时间都对当前的职位感兴趣。有时,你会想深入历史,寻找特定的问题和解决方案

    我会有代表当前位置的问题、解决方案和关系的表格。还有一个
    问题\历史记录
    解决方案\历史记录
    ,等等表格。这些将是问题的子表,但也包括
    foreign key (thing_id, thing_type) -> problems.id or solutions.id
    
    problem_id and solution_id 
    
    table things
      int id | int type | string name | text description | datetime created_at | other common fields...
      foreign key type -> thing_types.id
    
    table custom_attributes
      int id | int thing_id | string name | string value
      foreign key thing_id -> things.id