13

我正在寻找有关设计围绕版本化数据的数据模型的最佳方法的一些输入。会有一对多和多对多的关系,这些关系都可以随着版本的变化而变化。

我正在寻找一些不同的策略,最终目标是有效比较,如果可能的话只存储增量。

4

1 回答 1

17

介绍

这实际上是一个相当困难的问题。

版本控制对象很容易。它们之间的版本连接并没有那么多——您必须做出一些设计决策。例如:

  • 您是否需要在历史的任何时刻获取整个图表的“快照”?
  • 您想要永久删除而不是恢复已删除对象和连接的能力吗?
  • 您喜欢速度(并且不介意在版本之间复制整个图表)还是空间?

最重要的是,大多数“支持”表可能也需要“版本感知”。

设计

如果我是你,我可能会从以下起点开始:

在此处输入图像描述

OBJECT 和 CONNECTION 之间的符号是“类别”(又名继承、子类、泛化层次结构等)。

这种设计背后的基本思想是支持“快照”、“恢复”和“增量”功能:

  • 整个图有一个全局版本(又名“生成”),我们只存储它们之间的增量。
  • 每个对象都使用该全局代进行版本控制(与本地的、特定于对象的版本相反)。
  • 连接是对象,这使得它们也被版本化。
  • 每次一组对象进入存储库时,都会插入一个新的 GENERATION 并且:
    • 插入的对象被插入到 OBJECT 和 OBJECT_VERSION。
    • 修改后的对象被插入到 OBJECT_VERSION。
    • 已删除的对象被插入到 OBJECT_VERSION 中,DELETED = true。
    • 恢复的对象被插入到 OBJECT_VERSION 中,DELETED = false。顺便说一句,这使得删除/恢复周期可以重复多次。
    • 其余的对象都保持不变,所以我们不会浪费空间来复制未更改的数据。
  • 无法真正修改连接。要将子对象“移动”到新的父对象,请删除旧连接(通过如上所述设置 DELETED)并插入新连接。事实上,删除是连接支持的唯一一种修改。

查询将是这样的:

  • 要获得单个对象,请从其所有版本中选择仍不高于所需代的最高版本。如果此版本的 DELETED 为真,则此代中不存在对象。
  • 要在所需的代获取整个图的快照,请对所有对象执行上述操作并创建内存图。消除一个或两个端点都被删除的连接。
  • 要使对象连接到给定对象,请递归遍历 CONNECTION,但一旦遇到不符合上述条件的对象,就立即切断递归。

例子

假设您必须放置对象 A、B 和 C,其中 A 是 B 和 C 的父对象:

generation: 0

      A0
     /  \
   B0    C0

添加新对象 D:

generation: 0 1

      A0
     / | \
   B0  C0 D1

修改A和C并删除B:

generation: 0 1 2

      A0
      A2
     / | \
   B0  C0 D1
   B2* C2

   (*) OBJECT_VERSION.DELETED is true

将 C 从 A 移动到 D:

generation: 0 1 2 3

      A0
      A2
     / |* \
   B0  C0  D1
   B2* C2  |
           C3

ETC...

一些沉思

这种设计对不一致删除的异常情况是开放的:数据库不会保护自己不连接已删除和未删除的对象,或者在不删除连接的情况下将其中一个对象演变为已删除状态。在检查两个端点之前,您不会知道连接是否有效。如果您的数据是分层的,您可以使用“可达性模型”来代替:如果可以从某个根对象访问对象,则不会删除该对象。您永远不会直接删除该对象 - 您只需删除与它的所有连接。这对于文件夹/文件或类似的层次结构非常有效,您从“顶部”开始并向下搜索直到找到所需的对象。

“不可变”连接的替代方法是从 OBJECT_VERSION 继承 CONNECTION_VERSION 并将 PARENT_ID/CHILD_ID 放在那里,使用识别关系来确保正确建模菱形依赖关系。如果您需要跟踪移动历史,这可能很有用。

当然,这些只是粗略的笔触,我希望你能找到自己的方式......

于 2012-10-19T20:19:12.370 回答