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

时间:2015-03-23 19:15:34

标签: mysql sql database postgresql

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

为了清楚我的情况,我有一些实体(article)包含一些字段(namedescriptioncontent)。许多用户可以编辑同一篇文章。我想保留文章更新的历史(类似于版本控制),我想只保留差异,而不是更新文章的全部内容。顺便说一句,我使用PostgreSQL,但可以迁移到任何其他数据库。

UPD 打开赏金,所以这里有一些要求。你不需要完全满足它们。但如果你这样做会更好。然而,任何答案都非常感谢。所以我想要一个能力:

  1. 只保留差异,不得浪费我的空间。
  2. 获取某篇文章的任何修订版(版本)。但是获取文章的最后修订版必须非常快。其他修订的速度提升并不是那么重要。
  3. 获取某篇文章的任何差异(和差异列表)。文章可以在字段中进行更改:headerdescriptioncontent(如StackOverflow标题和内容中的更改),因此必须将其考虑在内。

2 个答案:

答案 0 :(得分:2)

在过去,我使用了diff-match-patch的优秀(和快速)结果。它适用于多种语言(我使用它的经验是在C#中)。我没有将它用于你所描述的过程(我们对合并感兴趣),但在我看来你可以:

  1. 保存文章的文本/标题/其他内容的初始版本。
  2. 进行更改时,使用diff-match-patch计算新编辑版本与数据库中已有版本之间的补丁。要在数据库中获取最新版本,只需按顺序将已生成的任何修补程序应用于原始文章。
  3. 保存新生成的补丁。
  4. 如果你想加快速度,你可以将文章的最新版本缓存在它自己的行/表中,然而你可以组织一些东西,这样获得最新版本就是一个简单的SELECT。这样,您就拥有了初始版本,补丁列表和当前版本,为您提供了一些灵活性和速度。

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

    您可以take a look at the patch demo查看其补丁的外观,并了解它们的大小。

    就像我说的那样,我并没有将它用于这种情况,但是diff-match-patch的设计或多或少都与你所说的完全相同。这个库位于我的简短软件列表中,当我对外部开发的库没有限制时,我可以使用它。

    更新:一些示例伪代码

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

    Articles
    --------
    id
    authorId
    title
    content
    timestamp
    
    ArticlePatches
    --------------
    id
    articleId
    patchText
    timestamp
    
    CurrentArticleContents
    ----------------------
    id
    articleId
    content
    

    然后一些基本的CRUD可能看起来像:

    插入新文章:

    INSERT INTO Articles (authorId, title, content, timestamp)
      VALUES(@authorId, @title, @content, GETDATE())
    INSERT INTO CurrentArticleContents(articleId, content) 
      VALUES(SCOPE_IDENTITY(),@content)
    GO
    

    获取每篇文章的最新内容:

    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
    

    更新文章的内容:

    //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)
    

    在特定时间点获取文章:

    //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]
    }
    

答案 1 :(得分:1)

我在工作场所有类似的问题。

我在更新后使用触发器将所有需要的数据记录到另一个表中(当然你只能保存差异字段),而真正的表上存在新的,而日志则存在于另一个表中表