两个 UNIQUE KEY 上的 MySQL CONSTRAINT,它们使用相同的 FOREIGN KEY ID

标签 mysql database-design constraints database-schema unique-key

我想创建一个 MySQL 表来保存用户之间的关系数据。用户 A 与 B 和用户 B 与 A 之间的关系可以不同。

示例:

  1. (从)Bob(到)Alice 的关系:0.9 - Bob 喜欢 Alice 的东西。
  2. (从)爱丽丝(到)鲍勃的关系:0.5 - 爱丽丝认为鲍勃的东西平庸。

我的问题:

我在引用用户表中 user_id 的两个外键上实现了两个约束作为唯一键。我可以这样做吗?它们是否被视为两个独立的 UNIQUE KEY?

我如何实现一个 CONSTRAINT 只允许每个(从)UserA(到)UserB 关系和(从)UserB(到)UserA 关系每个 user_id 出现一次?我的做法是否正确?

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;

我希望有人能提供帮助。

最佳答案

只保留这些 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 )。

关于两个 UNIQUE KEY 上的 MySQL CONSTRAINT,它们使用相同的 FOREIGN KEY ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9249441/

相关文章:

ASP.NET MVC : Save multiple values on autocomplete

mysql - 在 Windows 中安装 RMySQL?

django - 模型中 Django 文本字段的适当性

mysql - 如何从表中删除行而不从引用表中删除行?

sql - 有没有一种方法可以避免使用约束和触发器在特定表上删除行?

mysql - 设置mysql集群时出错

javascript - 如何从 MySQL 以键值对形式返回数据

sql - SQL中如何优雅地比较同一个表中的值

sql - 数据库设计 : should nested objects have their own table?

ios - 以编程方式访问自动布局约束