如果A
是的朋友B
,那么我应该同时存储值AB
和BA
,还是一个就足够了?两种方法的优缺点是什么?
这是我的观察:
- 如果同时保留两者,则在收到朋友的请求时必须同时更新两者。
- 如果我没有同时保留两者,那么我发现在
JOIN
对该表进行多次处理时很难。
目前,我以一种方式保持这种关系。
那么在这种情况下我该怎么办?有什么建议吗?
mysql
存储在亚马逊云中的内容。
如果A
是的朋友B
,那么我应该同时存储值AB
和BA
,还是一个就足够了?两种方法的优缺点是什么?
这是我的观察:
JOIN
对该表进行多次处理时很难。目前,我以一种方式保持这种关系。
那么在这种情况下我该怎么办?有什么建议吗?
mysql
存储在亚马逊云中的内容。
Answers:
我将存储AB和BA。友谊实际上是一种双向关系,每个实体相互联系。即使从直觉上讲,我们将“友谊”视为两个人之间的一个链接,但从关系的角度来看,它更像是“ A有一个朋友B”和“ B有一个朋友A”。两个关系,两个记录。
如果友谊是对称的(即不可能A
与B
对方成为朋友,反之亦然),那么我将使用检查约束存储单向关系,以确保每种关系只能以一种方式表示。
另外,我将放弃代理ID并改为使用复合PK(并且可能在反向列上也使用复合唯一索引)。
CREATE TABLE Friends
(
UserID1 INT NOT NULL REFERENCES Users(UserID),
UserID2 INT NOT NULL REFERENCES Users(UserID),
CONSTRAINT CheckOneWay CHECK (UserID1 < UserID2),
CONSTRAINT PK_Friends_UserID1_UserID2 PRIMARY KEY (UserID1, UserID2),
CONSTRAINT UQ_Friends_UserID2_UserID1 UNIQUE (UserID2, UserID1)
)
您不必说很难做到的查询,但是您始终可以创建一个视图
CREATE VIEW Foo
AS
SELECT UserID1,UserID2
FROM Friends
UNION ALL
SELECT UserID2,UserID1
FROM Friends
UNIQUE
INSERT
PRIMARY KEY (a,b)
UNIQUE
KEY (b,a)
UNIQUE
假设“友谊”始终是双向的,那么我可能会这样处理。
CREATE TABLE person (
person_id int IDENTITY(1,1) PRIMARY KEY,
...other columns...
)
CREATE TABLE friendship (
friendship_id int IDENTITY(1,1) PRIMARY KEY,
...other columns, if any...
)
CREATE TABLE person_friendship (
person_id int NOT NULL,
friendship_id int NOT NULL
PRIMARY KEY (person_id, friendship_id)
)
结果是您将其从“人”到“人”的多对多连接更改为从“人”到“友谊”的多对多连接。这将简化联接和约束,但是具有一个副作用,即允许在一个“友谊”中允许两个以上的人在一起(尽管可能会有更多的灵活性)。
您可能需要围绕友谊定义索引,而不是将行数加倍:
CREATE TABLE person
(
person_id INT NOT NULL AUTO_INCREMENT,
...
PRIMARY KEY (person_id)
);
CREATE TABLE friendship
(
friend_of INT NOT NULL,
friend_to INT NOT NULL,
PRIMARY KEY (friend_of,friend_to),
UNIQUE KEY friend_to (friend_to,friend_of)
);
这样,您就将索引的存储空间增加了一倍,而不是表数据的存储空间增加了一倍。结果,这将节省25%的磁盘空间。MySQL Query Optimizer将只选择执行索引范围扫描,这就是为什么在这里覆盖索引的概念很好用的原因。
以下是涵盖索引上的一些不错的链接:
警告
如果友谊不是相互的,那么您就有建立另一种关系的基础:跟随
如果friend_to不是friend_of的朋友,您可以简单地将这种关系排除在表外。
如果要为所有类型定义关系,无论它们是相互的还是不相互的,都可以使用以下表布局:
CREATE TABLE person
(
person_id INT NOT NULL AUTO_INCREMENT,
...
PRIMARY KEY (person_id)
);
CREATE TABLE relationship
(
rel_id INT NOT NULL AUTO_INCREMENT,
person_id1 INT NOT NULL,
person_id2 INT NOT NULL,
reltype_id TINYINT,
PRIMARY KEY (rel_id),
UNIQUE KEY outer_affinity (reltype_id,person_id1,person_id2),
UNIQUE KEY inner_affinity (reltype_id,person_id2,person_id1),
KEY has_relationship_to (person1_id,reltype_id),
KEY has_relationship_by (person2_id,reltype_id)
);
CREATE TABLE relation
(
reltype_id TINYINT NOT NULL AUTO_INCREMENT,
rel_name VARCHAR(20),
PRIMARY KEY (reltype_id),
UNIQUE KEY (rel_name)
);
INSERT INTO relation (relation_name) VALUES
('friend'),('follower'),('foe'),
('forgotabout'),('forsaken'),('fixed');
在关系表中,您可以安排关系以包括以下内容:
对于所有关系,无论该关系是相互的还是不相互的,这都应该更可靠。
如果您可以在应用程序中控制A的ID始终小于B的ID(对A,B元素ID进行预排序),则可以利用无OR的询问(选择id_A = a AND id_B = b的地方)来代替询问(id_A = a AND id_B = b)或(id_A = b AND id_B = a)),并使用另一方的近似值维护所需记录的一半。然后,您应该使用另一个字段来维护关系的状态(are-friends,a-to-to-b,b-soto-to-a,exfriends-a,exfriends-b),然后就完成了。
这就是我管理友谊系统的方式,这简化了系统,并使用了其他系统所需的一半行,只说A等于代码中的较低id值。