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会更有效.它是否正确?
对于关系数据库,选项 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中,我详细介绍了多态关联。
阅读数据库规范化.
您描述的方式中的空白将表明数据库设计不正确.
您需要拆分所有的表,以便在其中保存的数据是完全正常化,这将进一步为您节省大量的时间保证上下行,这是一个很大更好的做法是进入的习惯.
归档时间: |
|
查看次数: |
5222 次 |
最近记录: |