就像Cliffs的更新一样,感谢ChaosPandion的模板。
人
PersonID Int PK
网络
PersonID Int PK FK
OtherPersonID Int PK FK
OR
人
PersonID Int PK
网络
PersonID Int PK FK
FriendID Int PK FK
朋友
FriendID Int PK
OtherPersonID Int FK
++++++ 原帖在下面 ++++++
大家好,
我是一名网络开发人员,最近与一家公司合作开展了一个项目。目前,我正在与他们的DBA一起制定网站的架构,我们对几张桌子上的设计产生了分歧,我想就此问题提出一些意见。
基本上,我们正在开发一个实现“朋友”网络的网站。该站点的所有用户都将包含在具有(PersonID int identity PK等)的表tblUsers中。
我想要做的是创建第二个表tblNetwork,它将保存用户之间的所有关系,具有(NetworkID int identity PK,Owners_PersonID int FK,Friends_PersonID int FK等)。或者相反,删除NetworkID,并将Owners_PersonID和Friends_PersonID共享为主键。
这是DBA遇到问题的地方。他说“他只会在数据仓库架构中实现这种架构,而不是在网站上实现这种架构,这只是网络开发人员试图采取简单方法的另一个例子。”
现在显然,他的评论有点煽动性,这有助于激励我找到合适的答案,但更重要的是,我只想知道如何正确行事。我已经开发了数十年的数据库和编程,与一些顶尖的人一起工作,从未听过这种论点。
DBA想要做的不是将Owners_PersonId和Friends_PersonId存储在同一个表中,而是创建第三个表tblFriends来存储Friends_PersonId,并让tblNetwork拥有(NetworkID int identity PK,Owner_PersonID int FK) ,FriendsID int FK(来自TBLFriends))。所有那些tblFriends将会是(FriendsID int identity PK,Friends_PersonID(与人相关))。
对我而言,创建第三个表格本质上是过分的,除了为Friends_PersonID创建别名之外什么都没做,并且导致我必须添加(我认为不需要的东西)加入我的所有查询,更不用说了在每个查询上执行连接所需的额外周期。
我从技术上理解,他想要的是可能的,但它是否符合最佳实践?什么是最佳做法?
感谢阅读,感谢评论。
赖安
答案 0 :(得分:7)
如果我理解你,你提议:
Person PersonID PK
FriendList FriendListID, OwnerID, PersonID
DBA建议:
Person PersonID PK
FriendList FriendListID, OwnerID
FriendListEntry FriendListID, PersonID
您的方法需要为列表中的每个朋友添加多行。这将多次重复OwnerID,违反正常形式。 DBA的解决方案更加规范化,只有值依赖于FriendList表中的FriendListID。
这里最好的做法是成为DBA的好朋友。我会选择他的解决方案,因为它并不重要,你以后肯定需要他。
答案 1 :(得分:3)
对我来说唯一有意义的架构是:
Person
PersonID Int PK
Friend
PersonID Int PK FK
OtherPersonID Int PK FK
所以你可能有一个名为FriendList
的过程来执行这个很好的干净查询:
Select Person.*
From Friend
Inner Join Person On Friend.OtherPersonID = Person.PersonID
Where Friend.PersonID = @PersonID;
我不会宽恕选择所有列。
答案 2 :(得分:2)
如果Network.Owners_PersonID
以冗余方式存储在网络中,则您的设计会违反Third Normal Form。
但我不明白DBA的设计实际上有何帮助。我希望Friends
成为Users
和Networks
之间的多对多表:
CREATE TABLE tblUsers (
PersonID INT IDENTITY PRIMARY KEY
);
CREATE TABLE tblNetworks (
NetworkID INT IDENTITY PRIMARY KEY,
Owner_PersonID INT NOT NULL REFERENCES tblUsers
);
CREATE TABLE tblFriends (
NetworkID INT NOT NULL REFERENCES tblNetworks,
FriendID INT NOT NULL REFERENCES tblUsers,
PRIMARY KEY(NetworkID, FriendID)
);
换句话说,你有一个简单的多对多关系:
Users ----<- Friends ->---- Networks
另外,Networks
引用Users
只是为了识别给定网络的所有者。这样,给定网络只有一行,因此您无法通过更改某些行上的网络所有者来创建更新异常。
我认为这不会过分地将实体分成单独的表。您仍然可以获得给定网络的朋友列表:
SELECT ... FROM Networks n JOIN Friends f ON (n.NetworkID=f.NetworkID)
您可以通过这种方式从所有网络获取所有用户的朋友(传递给定用户的?
参数ID:
SELECT ... FROM Friends u
JOIN Friends f ON (u.NetworkID=f.NetworkID)
WHERE u.UserID = ?
在您的原始设计中,它几乎相同:
SELECT ... FROM Networks u
JOIN Networks f ON (u.Owner_UserID=f.Owner_UserID)
WHERE u.FriendID = ?
但优点是你已经消除了可能的更新异常。
答案 3 :(得分:1)
我想要做的是创建一个 第二个表,tblNetwork,那将 掌握所有关系 用户,具有(NetworkID int identity PK,Owners_PersonID int FK, Friends_PersonID int FK等)。要么 相反,删除NetworkID,和 拥有Owners_PersonID和 Friends_PersonID作为主要人员共享 键。
我认为没有任何问题。我同意NetworkID
是多余的 - 两个FK是表的自然键,所以你应该只使用它们作为主键,除非你有一些性能原因需要引用特定的通过代理人ID(在这种情况下你似乎没有)的关系。
答案 4 :(得分:0)
我说按你自己的方式去做。拥有第三个表格使编程部分更加痛苦。