【问题标题】:Logging changes for every column in a table记录表中每一列的更改
【发布时间】:2011-11-01 00:16:54
【问题描述】:

我正忙于创建一个系统,我需要跟踪系统中的每一个变化。换句话说,当数据库中的一列发生变化时,我需要知道是什么表,哪一列,什么时候发生的,由哪个用户,从什么值,到什么值。

我的第一个想法是为每个表创建第二个表以用于记录目的,其中包含 column_name、updated_by、updated_on、from_value、to_value 等字段(为简单起见,将 from_value 和 to_value 字段保留为字符串)。但是,这实际上会创建数据库的副本。

我的第二个选择是为所有表创建一个类似类型(table_name、column_name、updated_by、updated_on、from_value、to_value)的大型表,但这会导致表无法管理,因为更改会经常发生.

这两个选项都有相同的问题,我不确定如何引用表的列,最糟糕的是,我如何在应用程序生命周期的后期处理列名的更改。

任何想法和建议将不胜感激。

【问题讨论】:

  • 好吧,我可能会存储数据库对象 ID 而不是带有列/表/等名称的字符串,这可能会解决重命名列问题(如果 ID 保持不变,不确定如果是的话)。否则,很好的问题,我总是害怕自己做这样的事情......

标签: database-design


【解决方案1】:

我在这里做一些假设:

  • 您不受磁盘空间的限制
  • 您有一个重要的数据模型
  • 您需要能够以人类可读的格式报告您的审计/历史信息
  • 您没有满足极端的性能或可扩展性要求
  • 审计数据的受众是业务用户级别,而不是技术级别。

在这种情况下,我所知道的最佳解决方案是让“历史”成为您设计中的一流概念。引用的link GregL 对此进行了很好的描述;我更简单的实现基本上意味着在每个表上都有“valid_from”和“valid_until”和“operator_id”列,并使用“is_valid”而不是删除操作。

这比审核对单独表的更改要好,因为它允许您使用与常规数据访问代码相同的逻辑,创建历史上任何给定点的数据的完整图景,包括表之间的所有关系.反过来,这意味着您可以使用标准报告工具创建报告,回答诸如“哪个运营商更改了食品类别中所有产品的价格”、“1 月 1 日有多少产品的价格低于 100 美元?”之类的问题。等等

它确实会占用更多空间,并且确实使您的数据库访问逻辑更加复杂。它也不能很好地与 ORM 解决方案配合使用。

【讨论】:

  • 这是一个最喜欢的选项,但它并不完全符合我的需要。例如,在一个产品上,我希望有一个选项卡,用户可以在其中看到一个表格,其中包含对该产品所做的所有更改,时间和人员。 link abovehere 中的示例暗示我必须逐行比较才能列出更改历史记录表
  • 确实——但这(主要)是用户界面的问题。编写一个库函数来逐列区分两行并不难;当然,取决于您的前端代码。在此模型中,您将为每次更改显示一条记录;您可以将在行之间更改的每一列设为绿色。这比“用户 x 将价格从 y 更改为 z”更有意义(在我看来),因为更改往往是分组进行的——例如同时更改价格和描述。
  • 我想它可以这样工作。我将在表中(在前端)有一系列的行,其中包含大量“用户 x 将价格从 y 更改为 z”等。此外,该应用程序将有近 100 个表,我我害怕每张桌子都有第二张桌子。有些表有近 50 列
【解决方案2】:

我只记得这种功能的术语称为“审计”。在 Google 上快速搜索“数据库设计全面审计”会产生以下有趣的链接 - 可能值得一读:

http://www.simple-talk.com/sql/database-administration/database-design-a-point-in-time-architecture/

http://www.restfuldevelopment.net/david-kawliche/writing/time-after-time/

Best implementation for fully auditable data model?

http://www.sqlservercentral.com/articles/SQL+Puzzles/anaudittrailgenerator/2067/

他们只是让我印象深刻的那些,既然您知道“审计”这个关键词,您可能会找到更好的链接。

【讨论】:

  • 感谢您的文章。我环顾四周,发现了更多,但它与已经提供的答案相同
【解决方案3】:

查看我的answer for the question "history rows management in database" 它描述了我使用的解决方案以及该方法的优缺点。

基本上是一张大表,但变化以 XML 形式记录在一个字符串字段中。

编辑:

更改列名没有问题,因为每次更改都是一个 XML 字符串。
大多数时候我不得不深入研究历史,问题是“谁以及何时更改了该特定记录”,因此我可以选择少量具有相同 ID 的记录。
这种方法的问题是,如果您需要查找出现某些值的所有记录。它需要对整个表格进行全文搜索,而且速度非常慢。
您需要分析可能的搜索场景,然后选择最佳解决方案。

还有一件事需要考虑 - 历史记录永远不会更改,因此您可以拥有另一个数据库来保存历史记录的副本以进行交叉索引以便快速搜索。创建一个自动服务,该服务将不时从实时数据库中复制历史记录。

【讨论】:

  • 该信息很有用,但我仍然遇到的问题是,如果我更改表的列名,我将无法知道它之前是什么,因此我可以执行搜索(除非我在历史表中执行批量重命名)。这意味着我必须保留更改列名的日志。至于需要,我同意。这是一个很少使用的“非常重要的功能”。问题是,当需要它时,通常是由于导致金钱易手的法庭案件。
  • XML 选项对我来说不是很好,因为对表所做的更改需要通过选项卡提供,这样任何用户都可以随时查看谁更改了什么.
【解决方案4】:

这有点奇怪,但您可以在每个表中添加一个“InsertedOnTimestamp”列作为第二个主键。然后永远不要让用户更新表和创建只显示最新记录的视图。

Select * From Table
    Inner Join (Select ID, Max(InsertedOnTimestamp) as LastestRecord From Table Group By ID) as Latest 
    On Table.ID = LatestID AND Table.InsertedOnTimestamp = Latest.LatestRecord

听上去很乱,但还是一个想法……

【讨论】:

  • 这不是一个坏主意。但是,当您有一个包含 50 列的表并且您只更改其中一列时,问题就出现了。这种方法会不必要地创建一个包含重复数据的海量表。
猜你喜欢
  • 2011-09-12
  • 1970-01-01
  • 2021-08-31
  • 1970-01-01
  • 2010-09-21
  • 2016-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多