关于数据库设计:如何存储历史数据

How to Store Historical Data

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

我的同事说,这是不好的设计,因为我不应该有一个表的历史原因的精确副本,并应只需插入另一个记录到主动表标志表明它是历史的目的。

是否有处理历史数据存储的标准?在我看来,考虑到可能超过一百万条记录,我不想将我的活动记录与所有历史记录都放在同一张表中(我在考虑长期)。

您或您的公司如何处理?

我正在使用MS SQL Server 2008,但我想保留所有DBMS的通用和任意答案。


直接运作系统中支持的历史数据将会使你的应用程序要复杂得多比它本来是。通常,除非您有严格的要求在系统内处理记录的历史版本,否则我不建议您这样做。

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

  • 审计日志记录:这是富裕与审计表来完成。这是相当容易编写脚本生成通过从系统数据字典读取元数据来创建审计日志表和触发器的工具。这种类型的工具可用于改进审计日志记录到大多数系统。如果要实现数据仓库,也可以使用此子系统来更改数据捕获(请参见下文)。

  • 历史报告:报告历史状态,"在AS-"位置或随着时间的推移分析报告。它可能会通过quering上述排序的审计日志表来完成简单的历史报告要求。如果你有更复杂的需求,那么你可能会更经济,以实现对报告的数据集市,而不是试图直接整合历史进入操作system.Slowly改变尺寸是目前跟踪的最简单的机制和查询历史状态而远之历史记录跟踪可以自动化。通用处理程序并不难编写。一般情况下,历史报告没有使用先进的实时数据,让成批的刷新机制通常是罚款。这使您的核心和报告系统架构相对简单。

如果您的需求属于这两种类别之一,则最好不要在操作系统中存储历史数据。将历史功能分离到另一个子系统中,总体上可能会花费较少的精力,并且可以生成交易和审计/报告数据库,这些数据库可以更好地实现其预期目的。


我不认为这是做这件事的特定标准的方式,但我想我会扔在一个可能的方法。我在Oracle和我们内部的Web应用程序框架中工作,该框架利用XML来存储应用程序数据。

使用我们的东西称为主 - 详细模型,它是最简单的组成:

例如称为Widgets的主表通常仅包含一个ID。通常会包含不会随时间变化/不是历史数据的数据。

详细信息/历史记录表,例如称为Widget_Details,至少包含:

  • ID-主键。详细/历史ID
  • MASTER_ID - 例如,在这种情况下,所谓的"WIDGET_ID",这是FK到主记录
  • START_DATETIME-指示该数据库行开始的时间戳
  • END_DATETIME-指示该数据库行结束的时间戳
  • STATUS_CONTROL-单个字符列指示行的状态。"C"表示电流,NULL或"A"。将历史/存档。我们之所以只使用它,是因为我们无法在END_DATETIME为NULL时编制索引
  • CREATED_BY_WUA_ID-存储导致创建行的帐户的ID
  • XMLDATA-存储实际数据

因此,从本质上讲,一个实体首先要在主体中具有1行,在详细信息中具有1行。具有"C"的一个NULL结束日期和STATUS_CONTROL细节。
发生更新时,当前行将更新为具有当前时间的END_DATETIME,并且status_control设置为NULL(如果需要,则设置为" A")。一个新行中详细表创建,还是连接到相同主,与status_control"C",使得更新并存储在XMLDATA列中的新数据的人的ID。

这是我们历史模型的基础。创建/更新逻辑在Oracle PL / SQL包处理,这样你简单的传递函数的电流ID,用户ID和新的XML数据,并在内部它的所有更新/行插入来表示,在历史模式。开始时间和结束时间指示表中该行处于活动状态的时间。

存储是便宜,我们一般不删除数据,并希望保留审计线索。这使我们可以查看任何给定时间的数据。通过索引status_control ="C"或使用视图,杂乱是不完全的问题。显然,您的查询需要考虑到您应该始终使用记录的当前版本(NULL end_datetime和status_control ='C')。


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

如果你尝试其他方法很快你将面对的问题:

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

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


更改数据捕获:https://docs.microsoft.com/zh-cn/sql/relational-databases/track-changes/about-change-data-capture-sql-server?view=sql-server-2017

它在SQL Server 2008 R2中受支持,在SQL Server 2008中可能已受支持。


这个问题是很旧,但人们仍然在这个问题上的工作。因此,如果您使用的是oracle,则可能会对oracle闪回感兴趣:http://docs.oracle.com/cd/B28359_01/appdev.111/b28424/adfns_flashback.htm


只是想添加一个我开始使用的选项,因为我使用Azure SQL,而多表的事情对我来说太麻烦了。我在表上添加了插入/更新/删除触发器,然后使用" FOR JSON AUTO"功能将之前/之后的更改转换为json。

1
2
 SET @beforeJson = (SELECT * FROM DELETED FOR JSON AUTO)
SET @afterJson = (SELECT * FROM INSERTED FOR JSON AUTO)

这将返回更改前后的记录的JSON表示形式。然后,我将这些值存储在带有更改发生时间的时间戳的历史记录表中(我还存储当前关注记录的ID)。使用序列化过程,我可以控制在更改架构的情况下如何回填数据。

我从这里的链接中学到了这一点


您可以在表上创建实例化/索引视图。根据您的要求,您可以对视图进行全部或部分更新。请查看此内容以创建mview并记录。如何在SQL Server中创建实例化视图?


您可以使用MSSQL Server审核功能。在SQL Server 2012版本中,您将在所有版本中找到此功能:

http://technet.microsoft.com/zh-CN/library/cc280386.aspx


我知道这个旧帖子,但只想补充几点。
此类问题的标准是最适合这种情况的标准。了解此类存储的必要性以及历史/审核/变更跟踪数据的潜在使用非常重要。

审核(出于安全目的):对所有可审核表使用通用表。定义结构以存储列名,值之前和之后的字段。

存档/历史记录:对于诸如跟踪先前的地址,电话号码等情况,创建单独的表FOO_HIST会更好,如果您的活动事务表架构将来不会发生重大变化(如果您的历史表必须具有相同的结构)。
如果您期望表标准化,列的数据类型更改增加/删除,请以xml格式存储历史数据。用以下列(ID,日期,架构版本,XMLData)定义一个表。这将轻松处理架构更改。但是您必须处理xml,这可能会为数据检索带来一定程度的复杂性。


另一种选择是归档[每日|每小时|无论]运行数据基础。大多数数据库引擎支持的数据提取到归档。

基本上,这个想法是创建一个计划的Windows或CRON作业,

  • 确定操作数据库中的当前表
  • 选择从每一个表中的所有数据到CSV或XML文件
  • 导出的数据压缩到一个ZIP文件,优选地与生成的文件名中的时间戳,以方便归档。
  • 许多SQL数据库引擎附带了可用于此目的的工具。例如,在Linux上使用MySQL时,下面的命令可以在一个作业CRON用于调度提取:

    1
    mysqldump --all-databases --xml --lock-tables=false -ppassword | gzip -c | cat > /media/bak/servername-$(date +%Y-%m-%d)-mysql.xml.gz


    真正的问题是,您是否需要同时使用历史数据和活动数据进行报告?如果是的话让他们在一个表,分区并创建一个视图的活动记录在活动查询使用。如果你只需要在他们看起来偶尔(研究式法律问题或一些这样的),然后把它们放到单独的表。


    你可能只是分区表没有?

    "分区表和索引策略使用SQL Server 2008中
    当数据库表的大小增长到数百GB或更多时,加载新数据,删除旧数据和维护索引会变得更加困难。就在表的庞大规模使得这种操作需要更长的时间。甚至必须加载或删除的数据也可能非常大,这使得对该表执行INSERT和DELETE操作不切实际。微软SQL Server 2008数据库软件提供表分区,使这样的操作更易于管理。"