跟踪对象字段变化的最佳架构是啥?
Posted
技术标签:
【中文标题】跟踪对象字段变化的最佳架构是啥?【英文标题】:What is the best architecture for tracking field changes on objects?跟踪对象字段变化的最佳架构是什么? 【发布时间】:2011-01-09 06:09:57 【问题描述】:我们有一个基于 SQL 数据库构建的 Web 应用程序。几种不同类型的对象可以添加 cmets,其中一些对象需要字段级跟踪,类似于在大多数问题跟踪系统上跟踪字段更改的方式(例如状态、分配、优先级)。我们想显示更改是谁,之前的值是什么,以及新的值是什么。
在纯设计级别,最直接的方法是跟踪通用表中任何对象的每个更改,其中包含对象类型、对象主键、进行更改的用户的主键、字段名称的列,以及旧值和新值。在我们的例子中,如果用户在进行更改时输入了评论,这些也可以有一个评论 ID。
但是,随着这些数据的增长速度如此之快,这是最好的架构吗?将此类功能添加到已经大规模的应用程序中通常采用哪些方法?
[编辑] 我在这个问题上开始赏金主要是因为我想特别找出在处理规模方面最好的架构是什么。 Tom H. 的回答提供了丰富的信息,但推荐的解决方案似乎相当低效(对象的每个新状态都有一个新行,即使许多列没有改变)并且鉴于我们必须是还能够跟踪对用户创建的字段的更改。特别是,我可能会接受一个可以解释常见问题跟踪系统(JIRA 或类似系统)如何实现这一点的答案。
【问题讨论】:
【参考方案1】:为此,您有多种选择。您可以拥有基本上反映基表但还包括更改日期/时间、更改类型和用户的审计表。这些可以通过触发器进行更新。不过,这种解决方案通常更适合于幕后审计 (IMO),而不是解决特定于应用程序的需求。
第二个选项正如您所描述的那样。您可以拥有一个通用表,其中包含每个单独的更改以及类型代码,以显示更改了哪个属性。我个人不喜欢这种解决方案,因为它可以防止在列上使用检查约束,还可以防止外键约束。
第三个选项(这将是我根据给定信息做出的初步选择)是拥有一个单独的历史更改表,该表通过应用程序进行更新,并包括每个表的 PK 以及您选择的列将被跟踪。它与第一个选项略有不同,因为应用程序将负责根据需要更新表。在你的情况下,我更喜欢这个而不是第一个选项,因为你确实有你想要解决的业务需求,而不是像审计这样的后端技术需求。通过将逻辑放在应用程序中,您可以获得更多的灵活性。也许您不想跟踪某些更改,因为它们是维护更新等。
使用第三个选项,您可以将“当前”数据保存在基表中,也可以将每列历史保存在历史表中。然后,您需要查看最新行以获取对象的当前状态。我更喜欢这样,因为它避免了数据库中重复数据的问题,或者不必为相同的数据查看多个表。
所以,你可能有:
Problem_Ticket (ticket_id, ticket_name) Problem_Ticket_History(ticket_id、change_datetime、描述、评论、用户名)
或者,您可以使用:
Problem_Ticket (ticket_id, ticket_name) Problem_Ticket_Comments(ticket_id、change_datetime、comment、username) Problem_Ticket_Statuses(ticket_id、change_datetime、status_id、用户名)
【讨论】:
或者您可以使用审计表来捕获大部分信息(从而提供一种跟踪从任何地方所做的更改的方法)和一个 change_cmets 相关表来捕获来自 GUI 的更改的 cmets。仅取决于审核记录的重要性。 当然。如果审核是一项附加要求,那么您可以将两者结合起来。 @HLGEM - 所有交互,包括来自 GUI 的交互,都通过一个 API,因此对我们来说,应用程序触发器与数据库触发器一样可靠。但是,总的来说,您的设计听起来像是一个优雅的解决方案。 @Tom H. - 您如何处理建议设计中的比例?我也可能应该提到这些对象可以具有用户添加的属性,我们也希望能够跟踪这些属性。我们已经拥有大量数据,因此规模对我们来说非常重要。 Renesis 知道此解决方案。主要问题是“这些数据的增长速度有多快”。因此,解决方案是找到一种方法来限制存储的数据量。【参考方案2】:我不确定“问题跟踪”的具体方法,但我不会说有一种终极方法可以做到这一点。有许多选项可以实现它,每个选项都有其优点和缺点as illustrated here。
我个人会创建一个表,其中包含一些有关更改的元数据列和一个存储旧对象序列化版本的 xml 的列或您关心的任何内容。这样,如果您想显示对象的历史,您只需获取所有旧版本并重新水合它们并完成。一张桌子统领他们。
一个经常被忽视的解决方案是使用Change Data Capture。如果您真的担心,这可能会为您节省更多空间/提高性能。
祝你好运。
【讨论】:
【参考方案3】:这取决于您的确切要求,这可能不适合您,但对于带有触发器的数据库中的一般审计(因此前端甚至 SP 接口层都无关紧要),我们使用AutoAudit,而且效果很好。
【讨论】:
我不知道我会说前端和界面无关紧要。如果前端使用单个用户帐户连接到数据库,那么您需要构建一些东西来准确捕获实际进行更改的用户,而不仅仅是应用程序帐户。我没有使用过 AutoAudit,但我无法想象它可以在不至少对前端进行某种更改的情况下解决这个问题。 这是正确的 - 您只能在生成的触发器中使用有关连接的可用信息。如果它不在连接字符串或会话中或进入表的新行中,您可能没有所需的所有信息 - 但在所有设计中都是如此。您可以通过在每个连接开始时使用 SET CONTEXT_INFO 来解决这个问题。 在我们的例子中,我们有一个到数据库的单用户连接。不过,我对一般最佳做法感兴趣,因此感谢您的建议...+1【参考方案4】:这是我为实现您的目标而推荐的解决方案。
如下所示设计您的审核模型。
---------------- 1 * ------------ |审计事件类型 |---------|审计事件 | ---------------- ------------ | 1 | 1 | | ----------------- ------------- | 0,1 | + -------------------- ---------------- |审计事件评论 | |审计数据表 | -------------------- ---------------- | 1 | | | + ----------------- + 1 -------------- |审计数据列 |------------------|审计数据行 | ----- --------------.
AuditEventType
包含系统中所有可能的事件类型列表和相同的通用描述。
.
审计事件
包含有关触发此操作的特定事件的信息。
.
AuditEventComment
包含关于审计事件的可选自定义用户评论。评论可能真的很大,所以最好将它们存储在 CLOB 中。
.
审计数据表
包含受相应 AuditEvent 影响的一个或多个表的列表
.
AuditDataRow
包含相应 AuditDataTable 中受相应 AuditEvent 影响的一个或多个标识行的列表
.
审计数据列
包含相应 AuditDataRow 的零个或多个列的列表,这些列的值随其先前值和当前值而更改。
.
AuditBuilder
实现 AuditBuilder(构建器模式)。在事件开始时实例化它并使其在请求上下文中可用或与其他 DTO 一起传递。每次在代码中的任何位置对数据进行更改时,调用 AuditBuilder 上的适当调用以通知它有关更改。最后,在 AuditBuilder 上调用 build() 形成上述结构,然后将其持久化到数据库中。
确保事件的所有活动都在单个数据库事务中以及审计数据的持久性中。
【讨论】:
【参考方案5】:我不了解审计数据的实际使用场景,但是......您是否需要只跟踪更改?您是否需要“回滚”某些更改?您希望审核日志报告/查找的频率(和灵活性)如何?
我个人会调查类似的事情:
创建审核表。这有一个 ID、一个版本号、一个用户 ID 和一个 Clob 字段。
创建对象 #768795 后,在 AuditTable 中添加一行,其值: 编号=#768795 版本:0 用户:(创建新对象的用户 ID) clob:整个对象的 xml 表示。 (如果空间有问题,并且不经常访问此表,您可以使用 blob 并动态“压缩”xml 表示)。每次更改某些内容时,创建一个新版本,并将整个“序列化”对象存储为 XML 如果您需要创建审核日志,您就拥有所需的一切,并且可以使用简单的“文本比较”工具或库来查看及时更改的内容(有点像***)。
如果您只想跟踪字段的子集,或者因为其余字段是不可变的、不重要的,或者您迫切需要速度/空间,只需序列化您关心的子集。
【讨论】:
好问题 - 不,我们不想回滚更改。但是,我们确实希望能够输出对象的历史记录,就像常见的问题跟踪系统一样。我们希望该历史看起来像:“用户 X 将字段 Y 从值 A 更改为值 Z”【参考方案6】:我知道这个问题已经很老了,但是 sql 中内置的另一种可能性是 跟踪更改:
您可以在此链接上找到更多信息: SQL Server 2008 中的变更数据捕获 (CDC) 简介 http://www.simple-talk.com/sql/learn-sql-server/introduction-to-change-data-capture-(cdc)-in-sql-server-2008/
【讨论】:
【参考方案7】:我认为观察者是这种场景下的理想模式。
【讨论】:
以上是关于跟踪对象字段变化的最佳架构是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 requestAnimationFrame 游戏循环中跟踪时间/帧的最佳方法是啥?
跟踪是不是在 MongoDB 中单击了复选框/按钮的最佳方法是啥?