为版本化数据设计数据模型
Posted
技术标签:
【中文标题】为版本化数据设计数据模型【英文标题】:Designing a data model for versioned data 【发布时间】:2012-10-10 09:27:56 【问题描述】:我正在寻找有关设计围绕版本化数据的数据模型的最佳方法的一些意见。会有一对多和多对多的关系,这些关系都可以随着版本的变化而变化。
我正在寻找一些不同的策略,最终目标是进行有效比较,如果可能的话只存储增量。
【问题讨论】:
【参考方案1】:简介
这实际上是一个相当困难的问题。
版本控制对象很容易。它们之间的版本连接并没有那么多——您必须做出一些设计决策。例如:
您是否需要在历史的任何时刻获取整个图表的“快照”? 您希望永久删除还是恢复已删除的对象和连接? 您更喜欢速度(并且不介意在版本之间复制整个图表)还是空间?最重要的是,大多数“支持”表可能还需要“版本感知”。
设计
如果我是你,我可能会从以下起点开始:
OBJECT 和 CONNECTION 之间的符号是"category"(又名继承、子类、泛化层次结构等)。
这种设计背后的基本思想是支持“快照”、“恢复”和“增量”功能:
整个图有一个全局版本(又名“生成”),我们只存储它们之间的增量。 每个对象都使用该全局代进行版本控制(与本地、特定于对象的版本相反)。 连接是对象,这使得它们也被版本化。 每次一组对象进入存储库时,都会插入一个新的 GENERATION 并且: 一个插入的对象被插入到 OBJECT 和 OBJECT_VERSION 中。 修改后的对象被插入到 OBJECT_VERSION。 一个已删除的对象被插入到 OBJECT_VERSION 中,DELETED = true。 已恢复的对象被插入到 OBJECT_VERSION 中,DELETED = false。顺便说一句,这使得删除/恢复循环可以重复多次。 其余对象未受影响,因此我们不会浪费空间复制未更改的数据。 无法真正修改连接。要将子对象“移动”到新的父对象,请删除旧连接(通过如上所述设置 DELETED)并插入新连接。事实上,删除是连接支持的唯一一种修改。查询会是这样的:
要获取单个对象,请从其所有版本中选择仍不高于所需代的最高版本。如果此版本的 DELETED 为 true,则此代中不存在对象。 要在所需的代获取整个图的快照,请对所有对象执行上述操作并创建内存图。消除一个或两个端点都被删除的连接。 要将对象连接到给定对象,请递归遍历 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
等等……
一些沉思
这种设计对删除不一致的异常情况是开放的:数据库不会保护自己不连接已删除和未删除的对象,或者在不删除连接的情况下将其中一个对象演变为已删除状态。在检查两个端点之前,您不会知道连接是否有效。如果您的数据是分层的,您可以使用“可达性模型”来代替:如果可以从某个根对象访问对象,则不会删除该对象。您永远不会直接删除该对象 - 您只需删除与它的所有连接。这对于文件夹/文件或类似的层次结构非常有效,您从“顶部”开始并向下搜索,直到找到所需的对象。
“不可变”连接的替代方案是从 OBJECT_VERSION 继承 CONNECTION_VERSION 并将 PARENT_ID/CHILD_ID 放在那里,使用标识关系来确保diamond-shaped dependency is correctly modeled。如果您需要跟踪移动历史,这可能会很有用。
当然,这些只是粗略的笔触,希望你能找到自己的方式......
【讨论】:
版本相互独立。也许版本是一个不好用的词。它更像是父/子层次结构。以上是关于为版本化数据设计数据模型的主要内容,如果未能解决你的问题,请参考以下文章