Cha*_*han 35 mysql relational-theory
如果A是 的朋友B,那么我应该存储两个值AB和BA,还是一个就足够了?两种方法的优缺点是什么。
这是我的观察:
JOIN这张表进行多次处理时会很困难。目前,我以一种方式保持这种关系。
那么在这种情况下我应该怎么做呢?有什么建议吗?
dat*_*god 32
我会存储 AB 和 BA。友谊实际上是一种双向关系,每个实体都与另一个实体相连。尽管直觉上我们认为“友谊”是两个人之间的一个纽带,但从关系的角度来看,它更像是“A 有一个朋友 B”和“B 有一个朋友 A”。两个关系,两个记录。
Mar*_*ith 14
如果友谊是对称的(即不可能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)
)
Run Code Online (Sandbox Code Playgroud)
您不会说这使查询变得困难,但您始终可以创建一个视图
CREATE VIEW Foo
AS
SELECT UserID1,UserID2
FROM Friends
UNION ALL
SELECT UserID2,UserID1
FROM Friends
Run Code Online (Sandbox Code Playgroud)
假设“友谊”总是双向/相互的,我可能会像这样处理它。
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)
)
Run Code Online (Sandbox Code Playgroud)
结果是你把它从多对多连接从“人”变成了“人”,变成了从“人”到“友谊”的多对多连接。这将简化连接和约束,但有一个副作用,即允许两个以上的人建立一个“友谊”(尽管额外的灵活性可能是一个潜在的优势)。
您可能需要围绕友谊定义索引,而不是将行数加倍:
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)
);
Run Code Online (Sandbox Code Playgroud)
这样,您可以将索引的存储量加倍,而不是表数据的存储量。因此,这应该可以节省 25% 的磁盘空间。MySQL 查询优化器将选择仅执行索引范围扫描,这就是覆盖索引的概念在这里很有效的原因。
以下是有关覆盖索引的一些不错的链接:
警告
如果友谊不是相互的,你就有了另一种关系的基础:追随者
如果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');
Run Code Online (Sandbox Code Playgroud)
从关系表中,您可以安排关系以包括以下内容:
这对于所有关系都应该更加稳健,无论这种关系是相互的还是非相互的。