在数据库中设计存档.有些模式可能吗?

Paw*_*ulc 9 sql database database-design

我们目前正在做一个Web应用程序,其中一个功能是由用户创建事件.用户或管理员稍后可以删除这些事件.但是,客户端要求事件不是从数据库中实际删除,而是标记为已删除.用户应该只能看到未删除的事件,但管理员也应该能够浏览已删除的事件.这就是真正的功能.

现在我建议我们只需添加一个名为"status"的额外列,它将具有几个有效值:ACTIVE和DELETED.通过这种方式,我们可以区分正常(活动)和已删除事件,并创建非常简单的查询(SELECT*FROM EVENTS WHERE STATUS ='ACTIVE').然而,我的同事不同意.他指出,无论现在活动事件和已删除事件是否共享相同信息(因此它们可以存储在同一个表中),以后的需求,我的更改和客户端将需要存储有关已删除事件的一些其他信息(比如删除日期,谁删除了它,为什么要删除它 - 有点评论).他说,为了在将来满足这些要求,我们必须在EVENTS表中添加其他列,这些列将保存特定于已删除事件的数据,而不是活动事件.他提出了一个解决方案,其中创建了与EVENTS表具有相同模式的附加表(如DELETED_EVENTS).每个已删除的事件都将从EVENTS表中进行物理删除,并移至DELETED_EVENTS表.

我强烈反对他的想法.它不仅会使SQL查询更复杂,效率更低,而且完全违背了YAGNI.我也不同意他的观点,如果未来需求发生变化,我的想法将使我们在EVENTS表中创建额外的(不可为空)列.在我的场景中,我只需创建新表,如DELETED_EVENTS_DATA(将保存那些额外的存档数据),并在EVENTS表中添加引用键,以维护EVETNS和DELETED_EVENTS_DATA表之间的一对一关系.

然而,由于两个通常在软件和数据库设计上有相似观点的开发人员对于如何在数据库级别设计这些需求有如此截然不同的看法,我感到很困惑.我认为我们可能都朝着错误的方向前进,还有另一个(第三个)解决方案?或者只有一种替代方案?你如何设计这种要求?有关如何正确完成的任何模式或指导方针吗?任何帮助将深表感谢

Not*_*tMe 5

不要使用状态列。

至少您应该有一个 datedeleted 和一个 returnedby 列。仅仅知道某些内容被删除是没有帮助的,即使客户现在没有在第一次查看删除的事件时询问,他们也会想知道是谁删除的,以便找出原因。

如果事件表的大小可能会变得相当大,通常会将已删除/存档的数据完全移动到另一个表中。通常您会将这些表分配给不同的数据库文件。该文件通常位于不同的驱动器上,以保持性能。我并不是说一个全新的数据库,只是一个不同的数据库文件。

如果将其保留在同一个表中,则所有查询都应该有一个 where 子句(DateDeleted 为 null)。显然,如果信息被移动到不同的表中,您就没有这个要求。这就是为什么我推荐这种做事方式。


ant*_*nyv 0

OK,我们的处理方式如下。

我们在每个表上都有一个名为“已删除”的额外列,这是一个位字段。然后,正如您所说,您的查询非常简单,因为它只是一个 where 子句来过滤掉或保留它们。您唯一需要确保的是,您生成的任何报告或统计信息都会过滤掉已删除的记录。

然后,对于您正在谈论的想要捕获的额外信息,只需将这些额外信息放入单独的“审核”表中即可。在我们的例子中,我们已经使这个额外的表非常通用,它可以保存任何表的审计信息...请参见下面它是如何工作的...

Event
EventId   EventName   ...   Deleted
1         Dinner            0
2         Supper            1
3         Lunch             0
4         Lunch             1

Audit
AuditId    EntityTypeId     EntityId    ActionTypeId    ActionDateTime   ... etc 
1          1 (Event)        2 (EventId) 1 (Deleted)     2/1/2010 12:00:00
1          1 (Event)        4 (EventId) 1 (Deleted)     3/1/2010 12:00:00
Run Code Online (Sandbox Code Playgroud)

现在,如果您想要捕获其他实体(例如位置 - 其中位置是一个表),它看起来像这样......

Audit
AuditId    EntityTypeId     EntityId    ActionTypeId    ActionDateTime   ... etc 
1          1 (Event)        2 (EventId) 1 (Deleted)     1/1/2010 12:00:00
1          1 (Event)        4 (EventId) 1 (Deleted)     2/1/2010 12:00:00
1          2 (Event)        2 (LocationId) 1 (Deleted)     3/1/2010 12:00:00
1          2 (Event)        8 (LocationId) 1 (Deleted)     4/1/2010 12:00:00
1          2 (Event)        9 (LocationId) 1 (Deleted)     5/1/2010 12:00:00
Run Code Online (Sandbox Code Playgroud)

然后,当您想获取额外的审计数据时,您正在谈论的事情非常简单。查询看起来像这样

SELECT  *
FROM    Event E
        INNER JOIN Audit A
            ON E.EventId = A.EntityId 
WHERE   E.Deleted = 1
        AND A.EntityTypeId = 1 -- Where 1 stands for events
Run Code Online (Sandbox Code Playgroud)

此外,此审核表可以捕获其他事件而不仅仅是删除...这是通过使用 ActionTypeId 列来完成的。目前它只有 1(即删除),但您也可以有其他。

希望这可以帮助

编辑:

除此之外,如果我们有很强的审计要求,我们会执行以下操作...上述内容均不会更改,但我们创建了第二个名为“xyz_Audit”的数据库,该数据库捕获数据库中发生的每个操作的前和后操作。第二个数据库与第一个数据库具有相同的架构(没有审核表),只是每个表都有 2 个额外的列。

第一列是 PrePostFlag,第二列是 AuditId。因此,主键现在跨越 3 列:“xyzId”、“PrePostFlag”和“AuditId”。

通过这样做,我们可以让管理员完全了解谁在何时做了什么、更改了哪些数据以及如何更改,并且要取消删除记录,我们只需要更改主数据库中的已删除标志。

此外,通过将这些数据存储在不同的数据库中,我们可以对主要跨国数据库制定不同的优化、存储和管理计划。