我们计划在我们的数据库中引入简单的审计跟踪,为需要审计的每个表使用触发器和单独的历史表。
例如考虑表 StudentScore,它有很少的外键(例如 StudentID、CourseID)将其链接到相应的父表(学生和课程)。
Table StudentScore (
StudentScoreID, -- PK
StudentID ref Student(StudentID), -- FK to Student
CourseID ref Course(CourseID), -- FK to Course
)
如果 StudentScore 需要审计,我们计划创建审计表 StudentScoreHistory -
Table StudentScoreHistory (
StudentScoreHistoryID, -- PK
StudentScoreID,
StudentID,
CourseID,
AuditActionCode,
AuditDateTime,
AuditActionUserID
)
如果 StudentScore 中的任何行被修改,我们会将旧行移至 StudentScoreHistory。
在设计讨论期间提出的要点之一是将 StudentHistory 表中的 StudentID 和 CourseID 设为 FK,以保持参照完整性。支持这一点的论点是因为我们总是执行软(逻辑布尔标志)删除而不是硬删除,这有助于保持引用完整性以确保我们在审计表中没有任何孤儿 ID。
Table StudentScoreHistory (
StudentScoreHistoryID, -- PK
StudentScoreID,
StudentID ref Student(StudentID), -- FK to Student
CourseID ref Course(CourseID), -- FK to Course
AuditActionCode,
AuditDateTime,
AuditActionUserID
)
这对我来说似乎有点奇怪。我同意@Jonathan Leffler 的评论,即审计记录不应停止删除父数据。相反,如果需要,应该通过主表中的外键而不是审计表中的外键来处理。我想听听你的意见,以确保我不会错过将外键扩展到审计表的一些价值。
现在我的问题是: 在历史表中包含这些外键是一个好的设计吗?
任何关于关键论点的细节(例如性能、最佳实践、设计灵活性等)都将受到高度赞赏。
为了任何寻求特定目的和我们环境的人的利益:
目的:
- 维护关键数据历史
- 允许审核用户活动并支持重新创建场景
- 在有限的范围内允许回滚用户活动
环境:
- 事务数据库
- 并非每个表都需要审核
- 尽可能使用软删除,特别是针对静态/参考数据
- 很少有高度事务性的表使用硬删除