跟踪对象的字段更改的最佳架构是什么?

时间:2010-01-25 19:45:30

标签: sql architecture scalability change-tracking

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

在纯设计级别,跟踪通用表中任何对象的每个更改是最直接的,包括对象类型,对象主键,进行更改的用户的主键,字段名称的列,以及新旧价值观。在我们的例子中,如果用户在进行更改时输入了注释,这些也可以选择具有注释ID。

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

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

7 个答案:

答案 0 :(得分: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)

答案 1 :(得分:4)

我不确定“问题跟踪”的具体方法,但我不会说有一种最终方法可以做到这一点。有许多方法可以实现它,每个方案都有其好处和负面因素as illustrated here

我个人只创建一个包含有关更改的元数据列的表和一个存储旧对象的序列化版本的xml 的列或您关心的任何内容。这样,如果您想要显示对象的历史记录,您只需获得所有旧版本并重新补充它们并完成它们。一张表来统治它们。

一个经常被忽视的解决方案就是使用Change Data Capture。如果你真的担心的话,这可能会给你更多的空间节省/性能。

祝你好运。

答案 2 :(得分:1)

这取决于您的确切要求,这可能不适合您,但对于带触发器的数据库中的一般审核(因此前端甚至SP接口层无关紧要),我们使用{{3} },它的效果非常好。

答案 3 :(得分:1)

以下是我建议达到目标的解决方案。

设计审核模型,如下所示。



  ----------------  1      *  ------------                       
 | AuditEventType |----------| AuditEvent |                      
  ----------------            ------------                       
                                | 1    | 1                       
                                |      |                         
               -----------------        -------------            
              | 0,1                                  | +         
    -------------------                       ----------------   
   | AuditEventComment |                     | AuditDataTable |  
    -------------------                       ----------------   
                                                     | 1         
                                                     |           
                                                     |           
                                                     | +         
          -----------------  +             1  --------------     
         | AuditDataColumn |------------------| AuditDataRow |   
          -----------------                   --------------     



<强> AuditEventType

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

<强> AuditEvent

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

<强> AuditEventComment

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

<强> AuditDataTable

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

AuditDataRow

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

AuditDataColumn

包含各个AuditDataRow的零个或多个列的列表,其值已根据其先前和当前值进行更改。

<强> AuditBuilder

实施AuditBuilder(构建器模式)。在事件开始时实例化它并使其在请求上下文中可用或将其与其他DTO一起传递。每次在代码中的任何地方对数据进行更改时,都会调用AuditBuilder上的相应调用来通知它有关更改的信息。最后,在AuditBuilder上调用build()以形成上述结构,然后将其持久化到数据库。

确保事件的所有活动都在一个数据库事务中,同时保持审计数据的持久性。

答案 4 :(得分:0)

我不了解审计数据的实际使用情况,但是......您是否需要跟踪这些变化?你需要“回滚”一些变化吗?您希望审计日志报告/查找的频率(和灵活性)是多少?

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

创建AuditTable。它有ID,版本号,用户ID和clob字段。

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

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

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

答案 5 :(得分:0)

我知道这个问题很老但是内置于sql的另一个可能性是 跟踪更改:

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

答案 6 :(得分:-1)

我认为Observer是这种情况下的理想模式。