如何保留数据库中某些实体的更新(差异)

ale*_*ods 6 mysql sql database postgresql

保持数据库中某些实体的更新(差异)的最佳方法是什么?在 StackOverflow,我们可以编辑问题和答案。然后我们可以查看我们想要的问题或答案的任何修订。例如: 修改一些随机问题。也许有人知道它在 StackOverflow 中是如何实现的?

需要明确的是,在我的例子中,我有一些实体 ( article) 和一些字段 ( name, description, content) 。许多用户可以编辑同一篇文章。我想保留文章更新的历史记录(类似于版本控制),并且我想仅保留差异,而不是更新文章的全部内容。顺便说一句,我使用 PostgreSQL,但可以迁移到任何其他数据库。

UPD 开放赏金,所以这里有一些要求。你不需要完全满足他们。但如果你这样做的话,效果会好很多。尽管如此,我们非常感谢任何答案。所以我想拥有一种能力:

  1. 只保留差异,以免无端浪费我的空间。
  2. 获取某些文章的任何修订(版本)。但获取文章的最新版本必须非常快。其他修订的获取速度并不那么重要。
  3. 获取某些文章的任何差异(以及差异列表)。文章的字段可能会发生变化:headerdescriptioncontent(如 StackOverflow 的标题和内容会发生变化),因此必须考虑到这一点。

Pau*_*fin 7

过去,我使用diff-match-patch获得了出色(且快速)的结果。它可用于多种语言(我的经验是使用 C#)。我没有将它用于您所描述的确切过程(我们对合并感兴趣),但在我看来您可以:

  1. 保存文章文本/标题/其他内容的初始版本。
  2. 进行更改时,使用 diff-match-patch 计算新编辑的版本与数据库中已有版本之间的补丁。要获取数据库中的最新版本,只需按顺序将已生成的所有补丁应用到原始文章即可。
  3. 保存新生成的补丁。

如果您想加快速度,可以将文章的最新版本缓存在其自己的行/表/但是您组织的事物中,以便通过简单的 SELECT 获取最新版本。这样,您就可以获得初始版本、补丁列表和当前版本,从而为您提供一定的灵活性和速度。

由于您有一组按顺序的补丁,因此获取文章的任何版本只需将补丁应用到所需的补丁即可。

您可以查看补丁演示,了解其补丁的外观并了解它们有多大。

就像我说的,我还没有将它用于这种情况,但 diff-match-patch 的设计目的或多或少正是您所说的。当我对外部开发的库没有限制时,这个库就在我可以使用的软件的简短列表中。

更新:一些示例伪代码

例如,您可以像这样设置表(这假设还有一些其他表,例如作者):

Articles
--------
id
authorId
title
content
timestamp

ArticlePatches
--------------
id
articleId
patchText
timestamp

CurrentArticleContents
----------------------
id
articleId
content
Run Code Online (Sandbox Code Playgroud)

那么一些基本的 CRUD 可能如下所示:

插入新文章:

INSERT INTO Articles (authorId, title, content, timestamp)
  VALUES(@authorId, @title, @content, GETDATE())
INSERT INTO CurrentArticleContents(articleId, content) 
  VALUES(SCOPE_IDENTITY(),@content)
GO
Run Code Online (Sandbox Code Playgroud)

获取包含最新内容的所有文章:

SELECT 
  a.id,
  a.authorId,
  a.title,
  cac.content,
  a.timestamp AS originalPubDate
FROM Articles a
INNER JOIN CurrentArticleContents cac 
  ON a.id = cac.articleId
Run Code Online (Sandbox Code Playgroud)

更新文章内容:

//this would have to be done programatically
currentContent = 
    (SELECT content 
     FROM CurrentArticleContents 
     WHERE articleId = @articleId)

//using the diff-match-patch API
patches = patch_make(currentContent, newContent);
patchText = patch_toText(patches);

//setting @patchText = patchText and @newContent = newContent:
(INSERT INTO ArticlePatches(articleId, patchText, timestamp)
  VALUES(@articleId, @patchText, GETDATE())
INSERT INTO CurrentArticleContents(articleId, content, timestamp)
  VALUES(@articleId, @newContent, GETDATE())
GO)
Run Code Online (Sandbox Code Playgroud)

获取特定时间点的文章:

//again, programatically
originalContent = (SELECT content FROM Articles WHERE articleId = @articleId)
patchTexts = 
  (SELECT patchText 
  FROM ArticlePatches 
  WHERE articleId = @articleId
  AND timestamp <= @selectedDate
  ORDER BY timestamp ASCENDING)

content = originalContent
foreach(patchText in patchTexts)
{
  //more diff-match-patch API
  patches = patch_fromText(patchText)
  content = patch_apply(patches, content)[0]
}
Run Code Online (Sandbox Code Playgroud)