2

我一开始是故意让这个很模糊的。我正在寻找讨论以及哪些问题比我寻找硬性答案更重要。

我正在设计一个执行投资组合管理之类的应用程序。我到目前为止的设计是

  • 问题:需要解决的问题
  • 解决方案:针对一个或多个问题提出的解决方案
  • 关系:两个问题、两个解决方案或一个问题和一个解决方案之间的关系。进一步细分为:
    • 父子 - 某种分类/树层次结构
    • 重叠 - 两个解决方案或两个问题真正解决同一概念的程度
    • 地址 - 问题解决解决方案的程度

我的问题是关于这些事物的时间性质。问题突然出现,然后消失。解决方案有一个预期的解决日期,但在开发过程中可能会进行修改。随着问题和解决方案的发展,关系的程度可能会随着时间而改变。

那么问题来了:对这些东西进行版本控制的最佳设计是什么,这样我就可以同时了解我的投资组合的当前和历史观点?

后来:也许我应该提出一个更具体的问题,尽管@Eric Beard 的回答值得一提。

我考虑了三种数据库设计。我将充分展示它们的缺点。我的问题是:选择哪个,或者你能想出更好的东西吗?

1:问题(以及单独的解决方案)在版本控制中是自引用的。

table problems
  int id | string name | text description | datetime created_at | int previous_version_id

  foreign key previous_version_id -> problems.id

这是有问题的,因为每次我想要一个新版本时,我都必须复制整行,包括那个长description列。

2:新建关系类型:版本。

table problems
  int id | string name | text description | datetime created_at

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

3:使用更类似于Subversion的结构;将所有问题和解决方案属性移动到单独的表中并对其进行版本控制。

table problems
  int id

table attributes
  int id | int thing_id | string thing_type | string name | string value | datetime created_at | int previous_version_id

  foreign key (thing_id, thing_type) -> problems.id or solutions.id
  foreign key previous_version_id -> attributes.id

这意味着要加载问题或解决方案的当前版本,我必须获取属性的所有版本,按日期对它们进行排序,然后使用最新版本。那可能并不可怕。对我来说真正糟糕的是我无法在数据库中对这些属性进行类型检查。该value列必须是自由文本。我可以将该name列作为对具有列的单独attribute_names表的引用type,但这不会强制表中的类型正确attributes

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

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

4

5 回答 5

1

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

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

于 2008-08-14T20:57:36.573 回答
1

@盖乌斯

foreign key (thing_id, thing_type) -> problems.id or solutions.id

小心这些“多向”外键。我的经验表明,当您的连接条件必须在确定要连接的表之前检查类型时,查询性能会显着下降。它看起来并不优雅但可以为空

problem_id and solution_id 

会工作得更好。

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

于 2008-08-15T13:22:01.477 回答
1

你怎么看这个:

表问题
int id | 字符串名称 | 文字说明 | 日期时间 created_at

表问题
_revisions int 修订 | 内部 ID | 字符串名称 | 文字说明 | datetime created_at
外键 id -> questions.id

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

  1. 高效访问当前版本 - 像往常一样选择问题
  2. 直观且接近您要建模的现实的模式
  3. 架构中表之间的连接保持高效
  4. 使用每个业务事务的修订号,您可以对表记录进行版本控制,就像 SVN 对文件所做的那样。
于 2008-10-18T08:55:54.107 回答
0

我想有

选项4:混合

将常用事物属性移动到单继承表中,然后添加custom_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
于 2008-08-15T14:19:17.320 回答
0

选择一种数据结构是一个好主意,它可以使您对模型提出的常见问题易于回答。大多数时候,您很可能对当前职位感兴趣。有时,您会想要深入了解特定问题和解决方案的历史记录。

我会有代表当前位置的问题、解决方案和关系表。还有一个problem_history, solution_history, 等表。这些将是问题的子表,但也包含用于VersionNumber和的额外列EffectiveDate。关键是 ( ProblemId, VersionNumber)。

当您更新问题时,您会将旧值写入problem_history表中。因此,可以进行时间点查询,因为您可以挑选出problem_history在特定日期有效的记录。

在我之前做过的地方,我还创建了一个 UNION 视图problemproblem_history因为这有时在各种查询中很有用。

选项 1 使查询当前情况变得困难,因为您的所有历史数据都与当前数据混合在一起。

Option 3 is going to be bad for query performance and nasty to code against as you'll be accessing lots of rows for what should just be a simple query.

于 2008-10-31T09:50:35.683 回答