历史/时间表的最佳做法?


11

假设我有一个对象,其中包含我要跟踪历史记录的某些字段,以及某些我不想跟踪历史记录的字段。从规范化的角度来看,以下架构是否正确:

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

其中MyObjectHistory包含除最新修订版以外的所有跟踪字段。或者,应将所有跟踪的字段都放在一个表中,而所有修订(包括最新版本)都应在该表中,如下所示:

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

我同意@Joel
HaBo 2015年

Answers:


7

出于实际数据访问的原因,应使用第一个选项中的结构,而应将跟踪列值的所有版本(包括当前版本)保留在历史记录表中。

这样做的原因是,通常,当您要查看历史记录时,您希望包括当前版本和所有过去版本。当您不想查看历史记录时,可以将其清除。在许多情况下,这意味着要将历史记录完全隔离到单独的架构或数据库中。即使您将历史记录与当前数据保持在相同的架构中,任何查看历史数据(包括当前值)的查询也将变得更加复杂,因为它们必须将两个源进行合并。


2

我希望使用第一个版本,因为您可能几乎不需要查看历史记录,但是经常需要查看当前值。历史记录表应从触发器中填充,因此您不必担心数据通常会不同步。因此,假设您在MyObject中有百万条记录,然后在MyObjectHistory中有10,000,000条记录。您是否真的要加入具有这么多记录的表以获取当前值?

现在,如果您需要以比当前值更高的频率或更高的频率查询历史记录,那么第二个结构将起作用。(如果要显示某个特定日期的值,则可以在其中添加一个begindate和enddate字段,以简化查询。)

顺便说一句,我会在历史记录表中添加一个日期字段,以便能够知道更改发生的顺序。您不能依靠身份来确定时间顺序。PLus如果有关于previosu值的问题,并且当它更改时,您将需要知道。我还可以为更改来自的应用程序(如果您有多个应用程序)和/或进行更改的人输入值。


0

#1有两个重要原因。首先是HLGEM指出的尺寸问题,但还有其他重要的问题。

通常,随着时间的推移,您的审核跟踪将具有不断发展的需求。您可能最终想要跟踪数据库用户,更改时间等。审核跟踪要求和主表可能随时间推移而有所不同。最后,您可能希望在一段时间和一个完全独立的表之后清除审计跟踪数据。

当然,在某些情况下,您可能希望完全合并它们(就像我们在LedgerSMB中对税率所做的那样),因为历史数据可能用于当前计算,并且记录的数量可能相对较小。

但是,我建议,将对象存储在这样的表中很少会导致良好的标准化设计。以我的经验,您确实希望在良好的标准化存储和应用程序对象模型之间进行某种封装。


2
您所说的“良好的标准化存储与应用程序对象模型之间的封装”是什么意思?您将阐述这个想法还是举一个例子?
cubetwo1729
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.