像保存git的提交历史记录一样



我想为我的一个数据库实体构建一个类似git的版本控制系统。

模型如下:

Commit
  parent_commit_id
Change
  entity_id
  commit_id
  modifier (added, deleted, modified)
Entity

一个实体永远不会被真正删除,所以用户可以撤销提交并以一个有效的状态结束。

听起来很简单,但是:

  • 用户每次点击都会生成一个提交(性能非常重要)
  • 每次提交将有大约100个更改(修改,添加或删除)

因为我们只是存储更改,所以必须计算或存储当前状态。

选项1:保存每次提交的完整状态意味着我不仅要在提交中存储修改、添加和删除,还要存储所有未更改的实体。我认为这不是一个真正的选择,因为当系统运行时,将有超过2000万个实体。

选项2:使用递归公共表表达式计算当前状态。我不知道这是否足够快…

选项3:在一段时间后执行清理(如git gc)。这意味着我实际上要删除在清理时不再有效的所有实体。这不是一个真正的选项,因为我希望能够看到所有的更改,并返回到这些更改。

选项4:使用图形数据库(neo4j)?它能以合理的性能处理这样的规格吗?

你还有别的主意吗?

您使用Neo4j的想法很有趣。快速阅读http://en.wikibooks.org/wiki/Git/Internal_structure已经显示了git的复杂程度,以及提交的拓扑结构是一个"有向无环图"的事实,这有利于Neo4j。

但是要考虑的一件事是你计划的模型有多复杂?您想要git的部分或全部复杂性吗?如果是这样的话,像Neo4j这样灵活的数据库将是一个好主意。

如果您只想要跟踪单个文件的更改,而不关心多个并发用户,那么可以考虑旧的RCS系统,它存储最新的文件,加上与以前版本的一系列差异。这可以很容易地存储在两个表中(一个用于文件,另一个用于更改)。它与Dan的答案相反,后者存储第一个文件和从那里进行的更改。两种方法都可以工作,但是RCS方法能够比旧版本更快地检索最近的版本,而视频方法检索旧版本的速度最快。因为你看的是从旧的到最新的视频,所以他们这样做是有道理的,但我认为对于文件修改,你通常想先看最新的。有关这些方法的更全面的回顾,请查看Martin fowler关于Event Sourcing的博客。然而,这些方法并没有真正考虑多个并发用户,或者任何复杂的情况。但它们可能是更多的基础。

让我们重新考虑更复杂的模型。Neo4j是无模式的,允许您从简单开始,并根据需要增强功能。例如,您可以遵循以下路由:

  • 构建一个简单的类似rcs的文件修订系统,在单个图节点中包含最新的内容,以及到旧版本的链接链(或到旧版本的差异链)
  • 然后你决定你需要支持多个文件的提交,你添加树对象(描述在http://en.wikibooks.org/wiki/Git/Internal_structure),这些可以是真正的树结构的图形,与图形节点链接到文件对象节点。
  • 这些树被提交对象引用,这些对象本身与以前的提交链接在链中。一旦有了这些提交链,您可能就不再需要文件链了,因为您将遍历提交链。每次提交都指向一个指向文件的树。
  • 也许你决定支持分支,所以你添加标签和分支对象,链接到提交(从那里的树和文件)。这自然导致了显示分支和合并随时间发生的无环有向图。
  • 然后也许你甚至可以考虑添加refflogs,这也可以建模为图形。

当您完成上面的列表时,整个图变得更加丰富和复杂,支持更大的用例集。我认为这是一个建立数据模型的好方法。

从阅读http://en.wikibooks.org/wiki/Git/Internal_structure中可以清楚地看到,即使有了那里提供的简化描述,我们已经可以看到建模的很多价值,大部分是图形。链表,树和无环有向图。在我看来,Neo4j将是一个很好的技术来做到这一点。

那么如何开始呢?看一看,例如,在一些图表要点的例子。一个简单的似乎与此相关的方案是简单版本控制节点方案。然后从那里开始。

我必须考虑一些细节-但是如果你从视频处理中吸取教训-拥有原始的签入,并且每个版本都有增量,但是有一个'关键帧'属性来指示完整的快照,每10次提交,并且总是最新的版本。在不为每次提交存储完整数据的情况下,为您提供良好的性能…

相关内容

最新更新