良好的数据库表设计:一个表为每个实体混合不同的实体或单独的表

时间:2010-03-01 15:40:27

标签: database-design

什么是更好的数据库设计?

有一个可以包含不同“类型”记录的大表,例如:员工,汽车,手机,为了识别每种类型的记录,我们有一个名为type的列。

因此表格中的列会看起来像

id |类型|名称

1 |汽车|福特

2 |汽车|丰田

3 |电话|摩托罗拉

4 |员工|千斤顶

5 |员工| Aneesh

6 |电话|诺基亚

7 |电话|摩托罗拉

或每种类型都有不同的表

例如:

员工

id |名称

汽车

id |名称

电话

id |名称

这些表可以包含来自其他表的外键引用。现在,如果每个表都有不同的列,那么决定很简单,你不能在同一个表中拥有它。因此可能排除选项1(除非所有不常见的列都可以为空)。但是,如果这些不同的实体具有相似的列,那么什么是更好的设计呢?

支持和反对每个人的论据可能是什么?

4 个答案:

答案 0 :(得分:7)

我同意所有人 - 绝对使用单独的表格。通过使用单独的表来放松一下 - 只是因为你有更多的表,你的数据库不会变得更慢或更不易管理。

但是你获得了很多 - 你不必拥有许多对某种类型的实体毫无意义的字段,依此类推。正如许多人所指出的,你坚持2NF,这绝对是一件好事!

查看关于Simple Talk的这篇有趣的文章,名为

Five Simple Database Design Errors and how to avoid them

错误#1是作者称之为“常见查找表”的内容,听起来很像您正在尝试的内容 - 但是对于真实的实时数据。

阅读文章,内化其所有要求 - 优秀的东西,强烈推荐!

答案 1 :(得分:5)

由于它们是非常不同的类型,我建议将dm存储在单独的表中。这可以防止必须维护类型列表,因为它们都在自己的表中。此外,如果将来扩展其中一种类型(例如,您将为员工存储电话号码),您就不会获得任何奇怪的关系,例如汽车的电话号码。它还使您的数据库更易于理解和维护。

答案 2 :(得分:4)

Roald van Doorn是绝对正确的。如果您有一张桌子而且以任何方式扩展它,那么您将违反第二范式。正如William Kent所说,“当非关键字段是关于密钥子集的事实时,违反了第二范式。” Roald van Doorn的“员工电话号码”示例说明了违规行为。

William Kent的A Simple Guide to Five Normal Forms in Relational Database Theory是一篇很好的论文,可以在问自己一个数据库设计问题时进行评论。

答案 3 :(得分:1)

我会说上面的所有答案都是1.正确的,因为问题中引用的例子和2.几乎所有的时间都是正确的。

现在,我遇到的情况是单个表更好。它是如此罕见,当它出现时,我想知道我是否需要围绕一个单片(中立)实体进行架构。我很快就忽略了这种冲动 - 也许是在向别人询问,而且我没有充分陈述我的情况,我们就像往常一样这样做。

然后,事实证明,在游戏中为时已晚,我发现我应该制作一个中性实体类型的表。

这是一个让我的案例的例子:

假设有两种实体类型,一个公司和一个人。公司通常由一个人拥有,但有时另一家公司拥有一家公司。

坚持这一想法并加入其中,让我们说每个公司都有一个注册代理人,负责公司的合法创建。并且,进一步说明,注册代理人可以是个人或其他公司。

鉴于公司/儿童的所有者/父母可以是个人或公司,您可能会开始看到挑战。相比之下,如果只有人可以拥有公司,那么您的所有权链接表非常传统,包括列:OwnershipID(有点不必要),CorporateID,PersonID。

相反,您需要以下内容:OwnershipID,CorporationID,OwnerID,OwnerType 不管怎么说,你可以做到这一点,但至少可以说它不会很有趣。

继续我给出的示例,您需要为每个公司分配一个代理。通常,代理人是所有者(一个人)之一。在这种情况下,您确实想要链接回该人的一条记录。您不希望将此人的记录作为所有者,然后再将其作为代理记录(在代理表中)。这将是多余的。坏事会发生。 : - )

与该“问题”类似,注册代理人也可以是公司,例如律师事务所,注册会计师或商业申请公司,并提出一些典型的例子。就像代理人一样,代理公司真的不应该得到自己的记录。它需要链接回公司表中已有的公司存在记录。 [除了我最终说有公司表]

就像将每个公司与任何类型,个人或公司的所有者匹配的链接表一样,您可以拥有代理链接表:AgentRepresentationID,CorporationID,AgentID,AgentType。 ..但是,当你必须将相关代理 - 一些来自Person表,一些来自公司表时,它将是丑陋的(IMO)。

相反,在这种情况下,您可以看到中性实体类型如何有利。它会是这样的:

表:EntityAll 关键栏目: ENTITYID, EntityType(如果你坚持,则为EntityTypeID,链接以获取描述), EntityName(有关于名称和不同类型的问题......关于此帖子的主题)

链接表:CorporationOwnership 关键栏目: 所有权ID(再次,我的评论,这是不必要的), ChildEntityID(所拥有的实体;为清晰起见,将其命名为“Child”,我不会将其命名为) ParentEntityID(父实体)

链接表:AgentRepresentation 关键栏目: AgentRepresentationID(......我不会这么说), CorporationEntityID(正在表示的公司实体), AgentEntityID(来自Entity表,等同于此处代理的记录)

虽然您对我的架构可能没问题,但您应该对链接表中的列命名感到困扰。这让我很烦。通常,这些表中的第二个和第三个列名称与每个实体的相应表中的JOIN列完全匹配(哈哈,但是每个实体都没有拥有相应的表,因此您不能使链接表列名与源列名匹配,因为它们是同一列)。从技术上讲,这无关紧要,但它会打破你的命名约定,这些约定应该很重要,但不足以做到这一点。

如果我还没有把它推回家,那么你可以将它们拉到一起。你自己JOIN了EntityAll表来获得你需要的东西。

列出所有军团及其所有者(在T-SQL中):

SELECT Corp.EntityName as CorpName, Owner.EntityName as OwnerName
FROM EntityAll as Corp
JOIN CorporationOwnership as Link on (Corp.EntityID = Link.ChildEntityID)
JOIN EntityAll as Owner on (Link.ParentEntityID = Owner.EntityID)

因此,您可以采用相同的方法来获取代理,而不是拥有者。

我意识到这不是我们如何培养建筑事物的方法,但我非常强烈地认为我的解决方案可以消除冗余数据并使其更易于编码,管理和阅读。

如果你坚持认为我错了,请告诉我。建议如何使用单独的公司和人员实体表来构建我的示例。干杯!