1

有人建议我在项目中使用此处描述的表格,虽然我不能说为什么,但我认为这不是一个好主意。

MyTable(MyTableId PK,类型 INT NOT NULL,MyForeignKey INT NOT NULL)

MyForeignKey 可以根据 Type 的值指向各种表中的数据。当然,我们不能使用这样的模型来强制执行 FK 完整性,但是这个论点是否足以不使用它?

我会给你一个可以使用它的例子。假设您在系统中有一个 Notes 表来保存有关各种对象的注释;关于用户、文档等的注释。通常,我会这样建模:

注释(NoteId PK、Text VARCHAR(4000)、UserId INT NULL、DocumentId INT NULL、...)

我同事的建议是换一张这样的桌子:

注释(NoteId PK、文本 VARCHAR(4000)、ObjectType、ObjectId)

在第二个实现中,ObjectType 会告诉我们 ObjectId 是指向 Users 表还是 Documents 表中的一行。它的优点是如果我们想添加另一种类型的对象,数据库结构和代码需要的修改较少。

每种解决方案的优缺点是什么?

注意:我们永远不会拥有无数的对象类型。它应该保持在 10 以下。

事实上,我们的现实生活场景要复杂一些。它与权限系统有关,在该系统中,用户可能有权或可能无法访问各种类型的对象(文档、注释、事件等)

所以现在在我的数据库模型中,我有这些对象的表和其他表来建立它们与用户之间的关系(UserDocuments、UserNotes、UserEvents 等)。权限是通过这些链接表中的属性设置的。

我的同事提议使用一个单一的权限表,而不是像这样

权限(PermissionId PK、UserId INT、ObjectType、ObjectId、...其他权限字段...)

这是一个好主意吗?

另外,我们可以称之为 EAV 或 Open Schema 吗?这与我在这些主题上阅读的内容并不完全相同。

4

2 回答 2

2

这是个坏主意。当您在同一列中混合多种类型的数据,并添加相邻的类型列以消除歧义时,您几乎总是会后悔后果。

如果您正确地执行连接,您的连接条件将更加复杂,并且您的连接运行速度会更慢。如果你不正确地连接,你会得到错误。忘记检查类型列是错误的常见来源。

最好将指向不同表的指针放在不同的列中。但可能会有一个非常不同的设计,效果会更好。

您的多种类型对象的集合似乎非常适合称为“类表层次结构”的设计技术。这种技术基本上对类和子类使用单独的表,并具有共享的主键。共享主键需要应用程序中的代码将主键从类表传播到子类表。但这是值得的。

不需要单独的类型列,因为类表和子类表之间的连接会自动清除属于不同类的行。它光滑、简单、快速。

如果您在 SO 中在这里寻找类表继承或子类的关系建模的示例,您将获得数十个信息丰富的问答。


编辑将“类表层次结构”更改为“类表继承”。

于 2012-09-14T08:43:48.237 回答
0

好吧,老实说,机器人解决方案是正确的,但目的不同。正如您提到的此类类型的数量,这通常是驱动决策的唯一因素。

我假设我们正在谈论 OLTP 系统。因此,如果类型的数量相对较少,并且您确定它不会改变(特别是不会增长),您应该为不同的类型选择具有单独列的解决方案。

如果类型的数量很大(我认为 10 已经是一个很大的数字),您应该选择具有类型和键列的解决方案。

一般来说,多列变体更好,因为您可以使用 DBMS 机制来保持数据完整性,但在选择类型/键列变体时,您必须自己开发这些机制(即触发器和过程)。有时最好选择类型/键列变体,因为开发和维护工作不如结构更改工作那么大 - 如果您在系统的生产使用过程中没有看到在表中添加或删除 FK 列的任何问题,您仍然可以选择多列变体(在这种情况下它只是一个存储成本)。

于 2012-09-14T15:25:14.650 回答