FK列指向各种表

时间:2012-09-13 20:44:57

标签: database-design foreign-keys entity-attribute-value class-table-inheritance

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

MyTable(MyTableId PK,Type INT NOT NULL,MyForeignKey INT NOT NULL)

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

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

Notes(NoteId PK,Text VARCHAR(4000),UserId INT NULL,DocumentId INT NULL,...)

我的同事建议改为使用这样的表格:

Notes(NoteId PK,Text VARCHAR(4000),ObjectType,ObjectId)

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

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

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

事实上,我们的现实生活场景有点复杂。它与权限系统有关,用户可以访问或不访问各种类型的对象(文档,注释,事件等)

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

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

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

这是个好主意吗?

另外,我们可以称之为EAV还是Open Schema?这与我在这些主题上所读到的不完全相同。

2 个答案:

答案 0 :(得分:2)

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

如果正确连接,则连接条件会更复杂,并且连接速度会变慢。如果你的连接不正确,你会得到错误。忘记检查类型列是错误的常见原因。

最好将指针放在不同列中的不同表中。但是可能会有一种非常不同的设计可以更好地发挥作用。

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

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

如果您在SO中查找类表继承或子类关系建模的示例,您将获得数十个信息丰富的Q& As。


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

答案 1 :(得分:0)

嗯,在我的诚实意见中,机器人解决方案是正确的,但出于不同的目的。正如您所提到的那样,这些类型的数量很重要,而这通常是推动决策的唯一因素。

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

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

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