历史/时态表的最佳实践?

cub*_*729 12 normalization database-design

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

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,
)
Run Code Online (Sandbox Code Playgroud)

其中 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,
)
Run Code Online (Sandbox Code Playgroud)

Joe*_*own 7

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

这样做的原因是,一般来说,当您要查看历史时,您希望包括现在和所有过去的版本。当你不想看历史的时候,你希望它不碍事。在许多情况下,这意味着将历史完全隔离到单独的模式或数据库中。即使您将历史记录保存在与当前数据相同的模式中,任何查看历史数据(包括当前值)的查询也会更加复杂,因为它们本质上必须联合两个源。


HLG*_*GEM 2

我更喜欢第一个版本,因为您可能很少需要查看历史记录,但您经常需要查看当前值。历史表应该从触发器填充,因此您通常不需要担心数据不同步。因此,假设 MyObject 中有 100 万条记录,MyObjectHistory 中有 10,000,000 条记录。您真的想连接到包含那么多记录的表来获取当前值吗?

现在,如果您需要以比当前值更频繁或更高的频率查询历史记录,那么第二种结构就可以工作。(如果您要显示特定日期的值,我将在其中添加开始日期和结束日期字段以使查询更简单。)

顺便说一句,我会在历史表中添加一个日期字段,以便能够知道更改发生的顺序。你不能依赖身份来确定时间顺序。另外,如果对先前的值有疑问以及它何时发生变化,您将需要知道。我还可以输入进行更改的应用程序(如果您有多个应用程序)和/或进行更改的人员的值。