通用数据库表设计

Gaz*_*Gaz 9 sql sql-server database-design polymorphic-associations

只是想找出为以下场景设计表的最佳方法:

我的系统中有几个区域(文档,项目,组和客户端),每个区域都可以记录注释.

我的问题是我应该有这样一个表:

CommentID
DocumentID
ProjectID
GroupID
ClientID
etc
Run Code Online (Sandbox Code Playgroud)

只有一个id会有数据,其余的将是NULL,或者我应该有一个单独的CommentType表,并且我的注释表如下:

CommentID
CommentTypeID
ResourceID (this being the id of the project/doc/client)
etc
Run Code Online (Sandbox Code Playgroud)

我的想法是,从索引的角度来看,选项2会更有效.它是否正确?

Bil*_*win 6

对于关系数据库,选项 2不是一个好的解决方案。它被称为多态关联(如@Daniel Vassallo 所述),它打破了关系的基本定义。

例如,假设您在两个不同的行上的 ResourceId 为 1234。这些代表相同的资源吗?这取决于这两行的 CommentTypeId 是否相同。这违反了关系中类型的概念。有关更多详细信息,请参阅CJ Date 的SQL 和关系理论

另一个表明其设计有问题的线索是您不能为 ResourceId 声明外键约束,因为它可能指向多个表中的任何一个。如果您尝试使用触发器或其他东西来强制执行参照完整性,您会发现每次添加新类型的可评论资源时都需要重写触发器。

我会用@mdma 简要提到(但随后忽略)的解决方案来解决这个问题:

CREATE TABLE Commentable (
  ResourceId INT NOT NULL IDENTITY,
  ResourceType INT NOT NULL,
  PRIMARY KEY (ResourceId, ResourceType)
);

CREATE TABLE Documents (
  ResourceId INT NOT NULL,
  ResourceType INT NOT NULL CHECK (ResourceType = 1),
  FOREIGN KEY (ResourceId, ResourceType) REFERENCES Commentable
);

CREATE TABLE Projects (
  ResourceId INT NOT NULL,
  ResourceType INT NOT NULL CHECK (ResourceType = 2),
  FOREIGN KEY (ResourceId, ResourceType) REFERENCES Commentable
);
Run Code Online (Sandbox Code Playgroud)

现在每种资源类型都有自己的表,但串行主键由 Commentable 唯一分配。给定的主键值只能由一种资源类型使用。

CREATE TABLE Comments (
  CommentId INT IDENTITY PRIMARY KEY,
  ResourceId INT NOT NULL,
  ResourceType INT NOT NULL,
  FOREIGN KEY (ResourceId, ResourceType) REFERENCES Commentable
);
Run Code Online (Sandbox Code Playgroud)

现在评论引用可评论资源,并强制执行引用完整性。给定的评论只能引用一种资源类型。不可能出现异常或冲突的资源 ID。

在我的演示文稿SQL 中的实用面向对象模型和我的书SQL Antipatterns中,我详细介绍了多态关联。


Tom*_*len 5

阅读数据库规范化.

您描述的方式中的空白将表明数据库设计不正确.

您需要拆分所有的表,以便在其中保存的数据是完全正常化,这将进一步为您节省大量的时间保证上下行,这是一个很大更好的做法是进入的习惯.

  • 我确实正确地拼写了"正常化",我在英国. (4认同)

Gal*_*ian 0

在你给出的选项中,我会选择第二个。