【问题标题】:Maintaining audit log for entities split across multiple tables维护跨多个表拆分的实体的审计日志
【发布时间】:2010-10-02 05:13:49
【问题描述】:

我们将一个实体拆分为 5 个不同的表。其中 3 个表中的记录是强制性的。其他两个表中的记录是可选的(基于实体的子类型)。

其中一个表被指定为实体主控表。其他四个表中的记录由 master 的唯一 id 键控。

在每个表上都存在更新/删除触发器后,记录的更改会将历史记录(从触发器内部的已删除表)保存到相关的历史记录表中。每个历史表都包含相关的实体字段 + 时间戳。

因此,实时记录始终位于实时表中,而历史记录/更改则位于历史表中。历史记录可以根据时间戳列进行排序。显然,timestamp 列在历史表中是不相关的。

现在,更困难的部分。

  1. 记录最初插入到单个事务中。单个事务中将写入 3 或 5 条记录。
  2. 可以对 5 个表中的任何一个或所有表进行单独更新。
  3. 所有记录都作为单个事务的一部分进行更新。同样,3 或 5 条记录将在单个事务中更新。
  4. 数字 2 可以重复多次。
  5. 数字 3 可以重复多次。

应用程序应该根据仅作为单个事务写入的记录(仅点 1,3 和 5)显示时间点历史条目列表

我目前在使用仅根据时间戳数据检索历史记录的算法时遇到问题。

添加一个 HISTORYMASTER 表来保存有关事务的额外信息似乎可以部分解决问题。在每笔交易之前,都会在 HISTORYMASTER 中添加一条新记录。新的 HISTORYMASTER.ID 在事务期间保存到每个实体表中。 可以通过选择特定 HISTORYMASTER.ID 的第一条记录来检索时间点历史记录(按时间戳排序)

对于跨多个表的实体,是否有更优化的方法来管理基于 AFTER(UPDATE、DELETE)TRIGGER 的审计表?

【问题讨论】:

  • “历史记录点可以被检索...按时间戳排序”在我们的历史记录表中的行可以改变得比日期时间的粒度(我认为是 3 毫秒)更快,所以我们还有一个 EditNumber 列增加了UPDATE 触发器 - 正如其他人所说,“版本”可以绑定子历史记录

标签: sql-server triggers history logging audit


【解决方案1】:

您的 HistoryMaster 似乎类似于我们在其中一个系统中处理多个相关项目的历史记录的方式。通过一个点来挂起历史表中的所有相关更改,很容易创建一个使用历史主控器作为中心并附加相关信息的视图。它还允许您在不需要审核的历史记录中创建记录。

在我们的例子中,主表被称为 EntityAudit(实体是保留的“主要”项目),所有数据都存储在与审计相关的 EntityHistory 表中。在我们的案例中,我们将数据层用于业务规则,因此很容易将审计规则插入数据层本身。我觉得数据层是这种跟踪的最佳点当且仅当所有修改都使用该数据层。如果您有多个应用程序使用不同的数据层(或根本没有),那么我怀疑创建主记录的触发器几乎是唯一的方法。

如果您在审核中没有其他信息要跟踪(我们会跟踪进行更改的用户,例如,不在主表上的内容),那么我会考虑将额外的“主要”记录本身的审核 ID。您的描述似乎并未表明您对单个表的细微更改感兴趣,而只是对更新整个实体集的更改感兴趣(尽管我可能会错过阅读该内容)。如果您不关心次要编辑,我只会这样做。在我们的案例中,我们需要跟踪所有项更改,甚至是相关记录。

请注意,与源表相比,使用 Audit/Master 表的优势在于您对 History 表进行最小更改:单个 AuditID(在我们的示例中, Guid,虽然自动编号在非分布式数据库中会很好)。

【讨论】:

    【解决方案2】:

    您能否在实体主表中添加 TimeStamp / RowVersion 数据类型列,并将所有审计记录与之关联?

    但是对任何“子”表的更新都需要更新主实体表以强制更改时间戳/行版本:(

    或者在其中粘贴一个 GUID,以便在相关记录之一发生更改时进行更新。

    考虑一下,大声说出来,最好将一个表以 1:1 的比例连接到主实体,该表仅包含主实体 ID 和记录的“版本号”——TimeSTamp / RowVersion、GUI​​D、递增号码,或者别的什么。

    【讨论】:

      【解决方案3】:

      我认为这是试图在应用程序堆栈的最低级别(数据库)捕获“抽象”审计事件的症状。

      如果可能,请考虑在业务层中捕获审计事件。这将允许您捕获每个逻辑事务的历史记录,而不是逐行记录。日期/时间对于解决此类问题是不可靠的,因为它对于不同的行可能不同,而对于并发(或紧密间隔的)事务也是相同的。

      我了解到您已经询问了如何在数据库触发器中执行此操作。我不了解 SQL Server,但在 Oracle 中,您可以通过使用 DBMS_TRANSACTION.LOCAL_TRANSACTION_ID 系统包返回当前事务的 ID 来克服这个问题。如果您可以检索到等效的 SQLServer 值,则可以使用它将当前事务的记录更新捆绑到一个逻辑包中。

      【讨论】:

        猜你喜欢
        • 2017-01-09
        • 2015-05-31
        • 2010-09-29
        • 2010-11-10
        • 1970-01-01
        • 2018-04-26
        • 2018-01-25
        • 2013-08-27
        • 2011-06-28
        相关资源
        最近更新 更多