我想创建一个MySQL表来保存用户之间的关系数据。用户A到B和用户B到A之间的关系可以不同。
示例:
我的问题:
我在两个引用用户表中的user_ids的FOREIGN KEYS上实现了两个CONSTRAINTS作为UNIQUE KEY。我可以这样做吗?它们被视为两个独立的唯一键吗?
如何实现一个CONSTRAINT只允许每个user_id发生一次(from)UserA(to)UserB关系和(from)UserB(to)UserA关系?我是以正确的方式去做的吗?
SQL:
CREATE TABLE relationships (
relationship_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
from_user_id MEDIUMINT UNSIGNED NOT NULL,
to_user_id MEDIUMINT UNSIGNED NOT NULL,
relationship_level DECIMAL(1,1) NOT NULL,
PRIMARY KEY (relationship_id),
FOREIGN KEY (from_user_id) REFERENCES users (user_id)
ON DELETE CASCADE ON UPDATE NO ACTION,
FOREIGN KEY (to_user_id) REFERENCES users (user_id)
ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT from_to_relationship UNIQUE KEY (from_user_id, to_user_id),
CONSTRAINT to_from_relationship UNIQUE KEY (to_user_id, from_user_id),
INDEX relationship_from_to (relationship_id, from_user_id, to_user_id, relationship_level),
INDEX relationship_to_from (relationship_id, to_user_id, from_user_id, relationship_level)
) ENGINE=INNODB;
我希望有人可以提供帮助。
答案 0 :(得分:2)
只保留其中一个UNIQUE
约束 - 没有必要同时使用这两个约束。当行失败UNIQUE KEY (from_user_id, to_user_id)
时,它也会失败UNIQUE KEY (to_user_id, from_user_id)
,反之亦然,因此它们在逻辑上是等价的。即使只有一个UNIQUE
约束,当试图表示Alice和Bob之间的关系时,最多只能有一个{Alice,Bob}行,和最多一个{Bob,Alice }行。
至于性能(即遍历两个方向的关系),您可能需要考虑索引{from_user_id, to_user_id}
(用于“前向”遍历)和/或{to_user_id, from_user_id}
(用于“向后”遍历)。您甚至可能抛弃代理主键(relationship_id
)并转而使用自然PK,从而降低了索引的需求(二级索引对于群集表来说很昂贵,请参阅Understanding InnoDB clustered indexes,“群集的缺点”部分)。
在我看来,你的表应该是这样的:
CREATE TABLE relationships (
from_user_id MEDIUMINT UNSIGNED NOT NULL,
to_user_id MEDIUMINT UNSIGNED NOT NULL,
relationship_level DECIMAL(1,1) NOT NULL,
PRIMARY KEY (from_user_id, to_user_id), -- InnoDB is clustered, so naturally "covers" relationship_level as well.
FOREIGN KEY (from_user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION,
FOREIGN KEY (to_user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION,
INDEX relationship_to_from (to_user_id, from_user_id, relationship_level) -- Including relationship_level may or may not be a good idea.
) ENGINE=INNODB;
注意:您是否在INDEX中包含relationship_level
取决于您是否希望index-only scan处于“向后”方向。 PK的自然覆盖“前进”方向(因为InnoDB是clustered)。