如何存储历史数据

Aar*_*ron 152 database-design

我和一些同事讨论了存储历史数据的最佳方法.目前,对于某些系统,我使用单独的表来存储历史数据,并保留当前活动记录的原始表.所以,假设我有桌子FOO.在我的系统下,所有活动记录将进入FOO,所有历史记录将进入FOO_Hist.FOO中的许多不同字段可以由用户更新,因此我希望保持对更新的所有内容的准确帐户.除了自动递增的HIST_ID之外,FOO_Hist保存与FOO完全相同的字段.每次更新FOO时,我都会在FOO_Hist中执行一个插入语句,类似于:insert into FOO_HIST select * from FOO where id = @id.

我的同事说这是糟糕的设计,因为出于历史原因我不应该有一个表的精确副本,而应该只是在活动表中插入另一条记录,并带有一个标志,表明它是出于历史目的.

是否有处理历史数据存储的标准?在我看来,我不想把我的所有历史记录都放在同一个表格中,因为它可能超过一百万条记录(我在考虑长期).

你或你的公司如何处理这个问题?

我正在使用MS SQL Server 2008,但我想保持任何DBMS的通用和任意的答案.

Con*_*lls 75

直接在操作系统中支持历史数据将使您的应用程序比原本复杂得多.一般来说,我不建议这样做,除非你有一个硬性要求操纵系统内记录的历史版本.

如果仔细观察,历史数据的大多数要求分为两类:

  • 审计日志记录: 使用审计表可以更好地完成此操作.通过从系统数据字典中读取元数据,编写一个生成脚本来创建审计日志表和触发器的工具相当容易.此类工具可用于将审核日志记录改装到大多数系统上.如果要实现数据仓库,还可以使用此子系统进行更改的数据捕获(请参见下文).

  • 历史报告:随时间报告历史状态,"现状"或分析报告.通过查询上述类型的审计日志记录表,可以满足简单的历史报告要求.如果您有更复杂的要求,那么为报告实施数据集市可能比尝试将历史记录直接集成到操作系统中更为经济.

    到目前为止,缓慢变化的维度是用于跟踪和查询历史状态的最简单的机制,并且大部分历史跟踪可以是自动化的.通用处理程序并不难写.通常,历史报告不必使用最新数据,因此批量刷新机制通常很好.这使您的核心和报告系统架构相对简单.

如果您的要求属于这两个类别中的一个,那么最好不要将历史数据存储在您的操作系统中.将历史功能分离到另一个子系统可能会减少整体工作量,并生成更符合其预期目的的事务和审计/报告数据库.

  • 差不多.不过,最好使用触发器进行这种审计日志记录.触发器确保在审计日志中记录任何更改(包括手动数据修复).如果您有超过10-20个表进行审计,那么构建触发器生成器工具可能会更快.如果审核日志的磁盘流量存在问题,则可以将审核日志表放在一组单独的磁盘上. (5认同)

Chr*_*lls 36

我不认为有一种特殊的标准方法,但我认为我会投入一种可能的方法.我在Oracle和我们的内部Web应用程序框架中工作,该框架利用XML来存储应用程序数据.

我们使用一种称为Master - Detail模型的东西,它最简单的包括:

例如,Master TableWidgets通常只包含一个ID.通常包含不会随时间变化的数据/不是历史数据.

详细/历史表例如被称为Widget_Details至少包含:

  • ID - 主键.详细/历史ID
  • MASTER_ID - 例如在这种情况下称为'WIDGET_ID',这是主记录的FK
  • START_DATETIME - 指示该数据库行开始的时间戳
  • END_DATETIME - 指示该数据库行结束的时间戳
  • STATUS_CONTROL - 单个char列指示行的状态.'C'表示当前,NULL或'A'将是历史/存档的.我们只使用它,因为我们无法在END_DATETIME上将索引设为NULL
  • CREATED_BY_WUA_ID - 存储导致创建行的帐户的ID
  • XMLDATA - 存储实际数据

实际上,实体首先在主服务器中有1行,在细节中有1行.详细信息的结束日期为NULL,STATUS_CONTROL为"C".发生更新时,当前行更新为当前时间的END_DATETIME,并且status_control设置为NULL(如果首选,则为"A").在详细信息表中创建一个新行,仍然链接到同一个主服务器,其中status_control为"C",进行更新的人员的ID和存储在XMLDATA列中的新数据.

这是我们历史模型的基础.创建/更新逻辑在Oracle PL/SQL包中处理,因此您只需将函数传递给当前ID,您的用户ID和新的XML数据,并在内部执行所有行的更新/插入以表示历史模型中的行.开始和结束时间表示表中该行的活动时间.

存储很便宜,我们通常不会删除数据并且更喜欢保留审计跟踪.这使我们可以在任何给定时间查看我们的数据.通过索引status_control ='C'或使用View,混乱不是一个问题.显然,您的查询需要考虑到您应该始终使用记录的当前(NULL end_datetime和status_control ='C')版本.


Ale*_*der 12

我认为你的方法是正确的.历史表应该是没有索引的主表的副本,请确保您在表中也有更新时间戳.

如果你很快就尝试其他方法,你将面临问题:

  • 维护费用
  • 选择中的更多标志
  • 查询减速
  • 表,索引的增长


Ben*_*min 5

SQL Server 2016及更高版本中,有一个名为“ 临时表”的新功能,旨在以最小的开发人员精力来解决这一挑战。时态表的概念类似于更改数据捕获(CDC),不同之处在于时态表已抽象了大多数使用CDC时必须手动执行的操作。