第三范式:复合 PRIMARY KEY 与系​​统生成的代理 (IDENTITY)

Har*_* A. 6 normalization database-design sql-server sql-server-2014

我正在研究一个数据建模项目,我正在尝试为一个history只有四列的表找出最好的数据建模方法:

CREATE TABLE FooHistory
(
    SecurityID  INT (FK),     -- Part of the natural PK.
    FieldID     INT (FK),     -- Part of the natural PK.
    DateCreated DATETIME2(0), -- Part of the natural PK.
    Value       VARCHAR(50)
);
Run Code Online (Sandbox Code Playgroud)

此表中的自然复合 KEY 将是(DateCreated, SecurityId, FieldID),并且 ETL 过程每 30 分钟将向此表添加 ~ 2K 行。

问题

  1. 声明复合 PRIMARY KEY (PK)(DateCreated, SecurityId, FieldID)与添加新 IDENTITY 列(即系统生成的代理)并将其用作 PK 的优缺点?

  2. 我相信,如果我添加一个 IDENTITY 列并将其用作 PK,那么该表将不会处于第三范式(3NF)中,因为非 PK 列之间将存在函数依赖关系,即,(DateCreated, SecurityId, FieldID)Value.

  3. 由于此表保留了历史数据,因此我不希望将此表加入其他外部表,应用程序将主要使用 SELECT 语句与其进行交互。基于这些假设,将表保持在 3NF 中并声明复合 PK 是否值得,或者我应该将 IDENTITY 列添加到该表中?

MDC*_*CCL 8

根据您对正在考虑的案例的描述,似乎(a )通过表的属性附加一列以保存系统分配的代理*(为简洁起见,代理)是(b)多余的。IDENTITYHistory

当暂定的自然PRIMARY KEY (PK) 约束有可能被 FOREIGN KEY (FK) 约束定义引用时,保留代理的列可能很有用,但这种暂定的 PK 约束是

  • ,即它包含相对大量的列和/或
  • 要包含在潜在 PK 列中的值在字节方面物理上很重(显然,值的行为比值慢,因为例如,有关读取和写入过程的更大内存和磁盘空间使用,以及相应的对逻辑数据操作操作的响应速度的影响)。

因此,具有指向单个列的 FK 约束(1)在某种程度上可以作为上述自然 KEY 的“替代品”,并且(2)将保持较轻的值,这是一种值得评估的可能性。关于History手头的桌子,它在逻辑上既不宽,也没有沉重的物理脚手架支撑。

此外,为代理附加一列必然会使所讨论的表格更宽,因为它包含了一个暂时不需要的元素(也许?还有推测性的相应物理索引),因此它最终可能会表现得更慢。因此,考虑到它对数据库整体性能的影响,无论如何它可能不会提供任何实用价值。

这种特殊类型的列有时会有所帮助的情况是,当坚持代表独立实体类型的表时但是,如您所知,即使在这种情况下,每个特定表也需要 (i) 单独和 ( ii) 上下文分析以确定粘贴此类列是否方便(我想这就是您提出问题的原因)。

在逻辑层面,维护代理的列,当然,既不会捕获更多的业务领域含义(这会阻碍结果集的可读性和解释),也不会保护真正的行唯一性(保留无意义值的列是额外的非数据人工制品,所以您仍然必须确保真正数据元素的行唯一性)。见这个优秀的堆栈溢出的答案@PerformanceDBA有关这些方面的证据。

但是,您“可以”将其添加到History表中,“使用”它作为 PK,同时通过 (a) 组合的配置将列的组合声明(DateCreated, SecurityId, FieldId)为 ALTERNATE KEY (AK) UNIQUE 约束和 (b) 将所述组合中的每一列都指定为不可为空的(实际上保证行与真实数据元素相关的唯一性的安排)。这样,命名的非键列Value将在功能上依赖于

  • 保留代理的列,“使用”为 PK,
  • 由三个相关列组成的有意义和自然的AK;

因此,该表无论如何仍然符合 3NF §,尽管使用带有代理项的列不会提供好处,因此它会过度。

为什么它会过度的实际例子是:

  • History表将主要通过 SELECT 语句进行查询,这些 SELECT 语句包含一个或多个作为 WHERE 子句中的条件的自然 AK 的列(而包含代理项的列几乎不会被包含在内,因为它们对最终用户没有意义)。
  • 由于集成了额外的列,将 INSERT 操作 INTO 表会变慢。

重要的是要注意,在物理层面,建立一个良好的索引策略来服务于复合 PK 定义对于优化相关过程的功能至关重要,因此应该进行一些测试会议,例如,确定由适用的 INDEX(es) 配置辅助的合适的列顺序。


尾注

*系统分配的代理在 1979 年题为“扩展数据库关系模型以捕获更多含义”的论文中进行了评估,该论文由关系范式的创建者Edgar Frank Codd 博士撰写。在该论文中,规定不得向数据库用户显示代理值,即使在我看到的大多数数据库中都没有遵循该规则。目前的答案是基于这样一个假设,即在审议的场景中,代理就像普通的业务上下文值一样公开。

概念层面上,当实体类型(或实体原型)的每一个出现(即,当保留在 SQL 表中时)都由它自己的一个或多个属性的值唯一标识时,实体类型(或实体原型)是独立的(即,) 单独。甲依赖之一是,它需要一个(或多个)属性(一个或多个)属于其他实体类型,使得其每个的使用值的(一个或多个)的实例可以被唯一标识。

ALTERNATE KEY 是一列(或列的组合),其中包含唯一标识相关表的每一行但未被选为 PRIMARY KEY 的值;每个表可以有零个、一个或多个备用键。

§要分析为什么会这样,看的真正定义,正常形态标准化数据的关系模型的大型共享数据银行(1970),并在连续的正常形式(如乔尔·布朗随后的回答表明)的进一步正常化数据库关系模型(1971),两者都自然地由 EF Codd 博士工作。值得一提的是,原始关系模型(1970)不包括代理。