25

我们有一个构建在 SQL 数据库之上的 Web 应用程序。几种不同类型的对象可以添加注释,其中一些对象需要字段级跟踪,类似于在大多数问题跟踪系统上跟踪字段更改的方式(例如状态、分配、优先级)。我们想显示更改是谁,之前的值是什么,以及新的值是什么。

在纯设计级别,跟踪通用表中任何对象的每个更改是最直接的,其中列对象类型、对象主键、进行更改的用户的主键、字段名称和旧值和新值。在我们的例子中,如果用户在进行更改时输入了评论,这些也可以有一个评论 ID。

然而,随着这些数据的增长速度有多快,这是最好的架构吗?通常采用哪些方法将此类功能添加到已经大规模的应用程序中?

[编辑]我开始对这个问题进行赏金主要是因为我想特别找出在处理规模方面最好的架构是什么。Tom H. 的回答提供了丰富的信息,但推荐的解决方案似乎相当低效(对象的每个新状态都有一个新行,即使许多列没有改变)并且鉴于我们必须是还能够跟踪对用户创建的字段的更改。特别是,我可能会接受一个可以解释常见问题跟踪系统(JIRA 或类似系统)如何实现这一点的答案。

4

7 回答 7

7

为此,您有多种选择。您可以拥有基本上反映基表但还包括更改日期/时间、更改类型和用户的审计表。这些可以通过触发器进行更新。但是,此解决方案通常更适合幕后审计 (IMO),而不是解决特定于应用程序的要求。

第二个选项正如您所描述的。您可以拥有一个通用表,其中包含每个单独的更改以及类型代码,以显示更改了哪个属性。我个人不喜欢这种解决方案,因为它可以防止在列上使用检查约束,并且还可以防止外键约束。

第三个选项(这将是我在给定信息的初始选择)将有一个单独的历史更改表,该表通过应用程序更新,包括每个表的 PK 以及您将跟踪的列. 它与第一个选项略有不同,因为应用程序将负责根据需要更新表。在你的情况下,我更喜欢这个而不是第一个选项,因为你确实有你想要解决的业务需求,而不是像审计这样的后端技术需求。通过将逻辑放在应用程序中,您可以获得更多的灵活性。也许您不想跟踪某些更改,因为它们是维护更新等。

使用第三个选项,您可以将“当前”数据保存在基表中,也可以将每列历史保存在历史表中。然后,您需要查看最新行以获取对象的当前状态。我更喜欢这样,因为它避免了数据库中重复数据的问题,或者必须查看多个表以获取相同的数据。

所以,你可能有:

Problem_Ticket (ticket_id, ticket_name) Problem_Ticket_History (ticket_id, change_datetime, description, comment, username)

或者,您可以使用:

Problem_Ticket (ticket_id, ticket_name) Problem_Ticket_Comments (ticket_id, change_datetime, comment, username) Problem_Ticket_Statuses (ticket_id, change_datetime, status_id, username)

于 2010-01-25T19:59:33.190 回答
4

我不确定“问题跟踪”的具体方法,但我不会说有一种终极方法可以做到这一点。有许多选项可以实现它,每个选项都有其优点和缺点,如此处所示

我个人只会创建一个表,其中包含一些有关更改的元数据列和一个存储旧对象序列化版本的 xml 或您关心的任何内容的列。这样,如果您想显示对象的历史,您只需获取所有旧版本并重新水合它们并完成。一张桌子统治他们。

一种经常被忽视的解决方案是使用变更数据捕获。如果您真的担心,这可能会为您节省更多空间/性能。

祝你好运。

于 2010-02-18T06:52:37.557 回答
1

这取决于您的确切要求,这可能不适合您,但是对于带有触发器的数据库中的一般审计(因此前端甚至 SP 接口层都无关紧要),我们使用AutoAudit,它工作得很好.

于 2010-01-25T20:03:04.150 回答
1

这是我为实现您的目标而推荐的解决方案。

如下所示设计您的审计模型。


  ---------------- 1 * ------------                       
 | 审计事件类型 |---------| 审计事件 |                      
  ---------------- ------------                       
                                | 1 | 1                       
                                | |                         
               ----------------- -------------            
              | 0,1 | +         
    -------------------- ----------------   
   | 审计事件评论 | | 审计数据表 |  
    -------------------- ----------------   
                                                     | 1         
                                                     |           
                                                     |           
                                                     | +         
          ----------------- + 1 --------------     
         | 审计数据列 |------------------| 审计数据行 |   
          ----- --------------     



.

审计事件类型

包含系统中所有可能事件类型的列表和相同的通用描述。

.

审计事件

包含有关触发此操作的特定事件的信息。

.

审计事件评论

包含关于审计事件的可选自定义用户评论。评论可能真的很大,所以最好将它们存储在 CLOB 中。

.

审计数据表

包含受相应 AuditEvent 影响的一个或多个表的列表

.

审计数据行

包含受相应 AuditEvent 影响的相应 AuditDataTable 中一个或多个标识行的列表

.

审计数据列

包含相应 AuditDataRow 的零个或多个列的列表,这些列的值已随其先前值和当前值而更改。

.

审计生成器

实现 AuditBuilder(构建器模式)。在事件开始时实例化它并使其在请求上下文中可用或与其他 DTO 一起传递。每次在代码中的任何位置更改数据时,调用 AuditBuilder 上的适当调用以通知它有关更改。最后,在 AuditBuilder 上调用 build() 以形成上述结构,然后将其持久化到数据库。

确保事件的所有活动都在单个数据库事务中以及审计数据的持久性中。

于 2010-02-18T17:03:17.263 回答
0

我知道这个问题已经很老了,但是 sql 中内置的另一个可能性是 TRACK CHANGES:

您可以在此链接上找到更多信息:SQL Server 2008 中的变更数据捕获 (CDC) 简介 http://www.simple-talk.com/sql/learn-sql-server/introduction-to-change-data-capture -(cdc)-in-sql-server-2008/

于 2012-07-15T21:38:06.423 回答
0

不过,我不了解审计数据的实际使用场景……您是否只需要跟踪更改?您是否需要“回滚”某些更改?您希望审核日志报告/查找的频率(和灵活性)如何?

我个人会调查这样的事情:

创建审计表。这有一个 ID、一个版本号、一个用户 ID 和一个 Clob 字段。

  • 创建对象 #768795 时,在 AuditTable 中添加一行,其值:Id=#768795 版本:0 用户:(创建新对象的用户的 ID) clob:整个对象的 xml 表示。(如果空间有问题,并且不经常访问此表,您可以使用 blob 并动态“压缩”xml 表示)。

每次更改某些内容时,创建一个新版本,并将整个对象“序列化”为 XML 以防万一您需要创建审核日志,您拥有所需的一切,并且可以使用简单的“文本比较”工具或库来查看什么及时改变(有点像维基百科)。

如果您只想跟踪字段的子集,或者因为其余字段是不可变的、不重要的,或者您迫切需要速度/空间,只需序列化您关心的子集。

于 2010-02-19T12:45:58.523 回答
-2

我认为观察者是这种情况下的理想模式。

于 2011-02-10T07:51:53.707 回答