Database design 如何在一个表上建立具有多个m:n关系的数据库模型

Database design 如何在一个表上建立具有多个m:n关系的数据库模型,database-design,relational-database,entity-relationship,database-schema,Database Design,Relational Database,Entity Relationship,Database Schema,我目前正在建立一个数据库,它有大量的多对多关系。每个关系都是通过链接表建模的。例如: 一个人有很多工作,工作是由很多人完成的。一个人有很多房子,房子被很多人占据。一个人有很多他喜欢的餐馆,餐馆也有很多喜欢餐馆的人 首先,我设计如下: 桌子:人,工作,房子,餐馆,人,工作,人,房子,餐馆 关系1-n:Person->Person\u Job,Person->Person\u House,Person->Person\u Restaurant,Job->Person\u Job,House->Per

我目前正在建立一个数据库,它有大量的多对多关系。每个关系都是通过链接表建模的。例如:

一个人有很多工作,工作是由很多人完成的。一个人有很多房子,房子被很多人占据。一个人有很多他喜欢的餐馆,餐馆也有很多喜欢餐馆的人

首先,我设计如下:

桌子:人,工作,房子,餐馆,人,工作,人,房子,餐馆

关系1-n:Person->Person\u Job,Person->Person\u House,Person->Person\u Restaurant,Job->Person\u Job,House->Person\u House,Restaurant->Person\u Restaurant

这很快就导致了一个拥挤而复杂的ER模型

为了简化这一点,我将其建模如下:

标签:个人、工作、房子、餐厅、个人属性

关系1-n:人员->人员属性,工作->人员属性,房屋->人员属性,餐厅->人员属性

Person_Attributes表应该如下所示: 拟人 若比德 宅女 餐厅

如果存在人员-工作关系,我将添加一个条目,如下所示:

P1,J1,零,零

如果存在人际关系,我将添加一个条目,如下所示:

P1,空,H1,空

因此,第二个示例中的attributes表的条目数将与第一个示例中的link表的条目数相加相同

这大大简化了ER模型,只要我为personId+jobId、personId+houseId和personId+restaurantId建立索引,我认为不会对性能产生太大影响

我的问题是: 第二种方法是正确的建模方法吗?若否,原因为何? 我对性能影响的看法正确吗?若否,原因为何

我的意思的MySQL工作台示例可以在这里找到:


以我的拙见,我会选择第一款。它可能是一个更复杂的模型,但最终当您从表中提取信息时,它会使事情变得更容易,并且应用程序代码可能会变得更脏,或者对于其他程序员来说更不可读。此外,有些作者不推荐使用这样的多用途表


最后,你必须选择更适合你的东西。我们不了解整个情况,因此无法帮助您做出太多决定。但是,就你所说的,我肯定会选择第一个选项。

你的简化版本并不代表一个合适的关系模型。它更像是一个元数据模型


数据库中的表数应表示域中的逻辑实体数。这一点不应基于任意的想法而改变,即多少实体太多。

我认为第二种方法不正确,因为Person\u Attributes表将包含冗余数据。例如: 假设一个人喜欢10家餐馆,从事2份工作,有3间房子,你会有多达10*2*3个条目,其中应该是10+2+3(在3个链接表中……按照方法1)。想想拥有百万用户的缺点,如果在Person_attributes表中有3个以上的属性需要处理。。。 所以我会在你的问题中采用方法1

例如,假设您的Person_Attributes表有以下条目:

personId | houseId | jobId | restaurantId
------------------------------------------
P1      H1  J1  R1
现在,如果这个人喜欢餐厅R2和R3…桌子看起来像

P1      H1      J1      R1
P2      H1      J1      R2
P2      H1      J1      R3
表已经有冗余数据 他后来增加了工作J2。。 你的桌子看起来像

P1      H1      J1      R1
P2      H1      J1      R2
P2      H1      J1      R3
P1      H1      J2      R1
P2      H1      J2      R2
P2      H1      J2      R3
现在他又添了一个家H2。诸如此类……你明白我的意思吗?

你的设计违反了。您试图在一个表中存储多个“事实”,这会导致异常

Person\u Attributes表应该如下所示:personId jobId houseId restaurantId

所以,如果我只从事一份工作,一所房子,但有两家餐馆,我会储存以下物品吗

personId jobId houseId restaurantId
    1234    42      87         5678
    1234    42      87         9876
如果我增加第三家餐厅,我会复制其他栏目

personId jobId houseId restaurantId
    1234   123      87         5678
    1234   123      87         9876
    1234    42      87        13579 
完成了!等等,发生什么事了?我在增加新餐馆的同时换了工作。现在我被错误地与两个工作联系在一起,但是没有办法区分这一点和正确地与两个工作联系在一起

此外,即使与两个作业关联是正确的,数据不应该是这样的吗

personId jobId houseId restaurantId
    1234   123      87         5678
    1234   123      87         9876
    1234   123      87        13579 
    1234    42      87         5678
    1234    42      87         9876
    1234    42      87        13579 
它开始看起来像是jobId、houseId和restaurantId的所有不同值的集合。事实上,这是因为这个表试图存储多个独立的事实

正确的关系设计要求每个多对多关系都有一个单独的交集表。对不起,您没有找到快捷方式

(许多关于规范化的文章都说,超过3NF的高正规形式是深奥的,人们永远不必担心4NF或5NF。让这个例子来反驳这一说法。)


如果您对使用NULL有何评论:那么您在强制唯一性方面会遇到问题,因为
主键
约束要求所有列都不为NULL

personId jobId houseId restaurantId
    1234   123      87         5678
    1234  NULL    NULL         9876
    1234  NULL    NULL        13579 
另外,如果我在上表中添加第二个house或第二个jobId,我应该将其放在哪一行?你可能会得到这样的结果:

personId jobId houseId restaurantId
    1234   123      87         5678
    1234  NULL    NULL         9876
    1234    42    NULL        13579 
现在,如果我解除restaurantId 9876的关联,我可以将其更新为NULL。但这会留下一行空值,我真的应该删除它

personId jobId houseId restaurantId
    1234   123      87         5678
    1234  NULL    NULL         NULL
    1234    42    NULL        13579 
然而,如果我解除了与餐厅13579的关联,我可以将其更新为NULL并保留行

personId jobId houseId restaurantId
    1234   123      87         5678
    1234  NULL    NULL         9876
    1234    42    NULL         NULL 
但是如果列中有空缺,我是否应该合并行,将jobId移到另一行

personId jobId houseId restaurantId
    1234   123      87         5678
    1234    42    NULL         9876
问题是,现在添加或删除关联变得越来越复杂,需要使用多个SQL语句进行更改。您将不得不编写大量乏味的应用程序代码来处理这种复杂性

但是,如果您为每多对多关系定义一个表,那么所有的各种更改都很容易。您确实需要拥有那么多表的复杂性,但是需要这样做