代码之家  ›  专栏  ›  技术社区  ›  RageZ

数据库版本控制

  •  3
  • RageZ  · 技术社区  · 16 年前

    我已经做了一些项目(CMS和EC系统),需要有一些数据版本。

    通常我会带着这种模式

    +--------------+
    + foobar       +
    +--------------+
    + foobar_id    +
    + version      +
    +--------------+
    

    这很有效,但我想知道是否有更好的方法。该解决方案的主要问题是您必须始终使用子查询来获取最新版本。

    即。:

    SELECT * FROM foobar WHERE foobar_id = 2 and version = (SELECT MAX(version) FROM foobar f2 WHERE f2 = 2)
    

    这使得大多数查询变得更加复杂,并且也存在一些性能缺陷。

    谢谢

    7 回复  |  直到 16 年前
        1
  •  5
  •   Jim Mitchener    16 年前

    我更喜欢将历史数据放在另一个表中。我会制作foobar_历史或类似的东西,并制作一个FK到foobar_id。这将使您不必同时使用子查询。这样做还有一个额外的优点,就是不会让大量的历史数据污染主数据表,而在访问它的99%时间里,您可能不希望看到这些数据。

    不过,您可能希望触发更新此数据,因为这需要您将当前数据复制到_历史记录中,然后进行更新。

        2
  •  2
  •   Amr ElGarhy    16 年前

        3
  •  2
  •   ewernli    16 年前

    赞成的意见:

    • 易懂
    • 不需要对(现有)数据库架构进行重大更改
    • 不需要复制另一个表中的旧数据,只更新标志。

    否则,您可以依赖一个单独的历史记录表,正如几个答案中所建议的那样。

    赞成的意见:

    • 从实际数据中清除历史记录
    • 在删除实体的情况下,可以在实际数据及其历史记录之间进行db级级联删除

    欺骗:

    • 如果需要完整的历史记录(即旧数据+当前数据),则需要2个查询(或一个联合)
    • 将更新与数据的最新版本相对应的行。我听说更新比插入慢,这取决于更改的数据的“大小”。

    什么是最好的将取决于您的用例。我必须处理一个文档管理系统,在这个系统中,我们希望能够对文档进行版本设置。但我们也有类似于恢复到旧版本的功能。使用布尔值来加速需要最后一个布尔值的操作更容易。如果您有真实的历史数据(永远不会改变),那么一个专用的历史表可能会更好。

    历史的概念是否适合您的领域模型?如果没有,那么您有一个不同于概念域模型的db模式。如果在域级别,实际数据和旧数据需要以相同的方式处理,那么有两个表会使设计复杂化。只需考虑您需要返回完整历史(旧+新)的情况。最简单的解决方案是每个表都有一个类,但是不能像只有一个表那样轻松地返回列表。但如果这是两个截然不同的概念,那么让历史成为您设计中的第一流是很好的。

    我还推荐M。Fowler在处理时态数据时也很有趣: Patterns for things that change with time

        4
  •  1
  •   Carsten    16 年前

    您可以通过使用表上的视图简化查询,该视图将筛选到最新版本。这只会使查询看起来更好,但仍会带来性能开销。

        5
  •  1
  •   Damir Sudarevic    16 年前

    常用的方法是添加一列 version_status 对于当前/过期。另外需要注意的是,如果您在同一个表中保留新记录和旧记录,那么您的实体应该有一个业务(自然)键,比如 name + pin

    TABLE foobar(foobar_id PK, business_key, version, version_status, .....)
    
    SELECT * 
    FROM foobar 
    WHERE business_key = 'myFoobar3' AND version_status = 'current'
    

    当决定将记录历史保存在同一个表中时,或者将它移到单独的表中时,请考虑其他具有表的表。 foobar_id 作为外键。发布新版本时,现有外键是指向新PK还是指向旧PK?如果您想保留关系的历史记录,您可能希望将所有内容都保存在同一个表中。如果新版本很重要,您可以考虑将过期的行移到另一个表——尽管这不是必需的。

        6
  •  0
  •   len    16 年前

    从中选择*( 选择a* 来自foobar a 其中foobar_id=2

        7
  •  0
  •   KenFar    16 年前

    这取决于有多少表需要版本控制,以及是否有事务性ore报告系统。

    如果只是几个事务表,那么只要性能问题不太严重,您的处理方式就可以了。您可以通过为当前行添加一列和一个触发器来简化查询,该触发器将更新前一行使其成为非当前行。

    但是,如果您有很多表,或者额外的行减慢了一些查询的速度,那么我会按照其他人的建议,使用历史表和历史触发器。请注意,您可以生成该代码以使其更易于开发&维持。