【问题标题】:What is the best practice for designing an SQL table that relates to table A, table B, or table A and B?设计与表 A、表 B 或表 A​​ 和 B 相关的 SQL 表的最佳实践是什么?
【发布时间】:2017-05-22 19:56:06
【问题描述】:

假设我有三张桌子。我将尽可能简化这些表格来说明设计问题:

用户:

CREATE TABLE users (user_id INT PRIMARY KEY);

网络:

CREATE TABLE networks (network_id INT PRIMARY KEY);

网络用户:

CREATE TABLE network_users (
     network_id INT, 
     user_id INT, 
     PRIMARY KEY(network_id, user_id), 
     FOREIGN KEY(network_id) REFERENCES networks(network_id), 
     FOREIGN KEY(user_id) REFERENCES users(user_id)
);

如上所示,用户与网络具有多对多关系,如网络用户表中所述。到目前为止,这一切都很传统。

现在这是我的问题:

假设我想添加一个消息表,并且我希望能够存储发送到的消息:

  1. 特定用户,
  2. 一个特定的网络,
  3. 或网络内的用户

消息表的最佳设计方法是什么?

我可以像这样构造一个消息表:

CREATE TABLE messages (
    message_id INT PRIMARY KEY, 
    network_id INT, 
    user_id INT, 
    FOREIGN KEY(network_id) REFERENCES networks(network_id), 
    FOREIGN KEY(user_id) REFERENCES users(user_id)
);

地点:

  1. 发送给特定用户的消息设置了 user_id 字段,并且 network_id 字段为 NULL
  2. 发送到特定网络的消息设置了 network_id 字段,并且 user_id 为 NULL
  3. 发送给网络内用户的消息同时设置了 network_id 和 user_id 字段

但这是最好的方法吗?由于 network_id 和 user_id 字段可能为空,我必须创建一个单独的主键 (message_id),而不是使用复合主键(network_id 和 user_id),否则会这样做。

【问题讨论】:

  • 如果网络 N 中的用户 A 与网络 O 中的用户 A 不同(向特定网络中的特定用户发送消息),则用户和网络不是多对多关系,仅在一对多中。
  • 嗯,你能进一步解释一下吗?一个用户可以在多个网络中,一个网络可以包含多个用户。这不是网络和用户之间的多对多关系吗?消息与网络中用户的消息关系#3 将是一对多关系,但这是消息和 network_users 之间的一对多关系;我认为 messages-to-network_users 关系不会影响 users-to-networks 关系。
  • 如果同一用户可以在多个网络中,那么向特定网络中的特定用户发送消息是没有意义的。我只需要将消息发送给用户。
  • 上面的例子只是为了说明。我的实际情况要复杂得多,但可以说所有三个关系都有有效的用例。例如,我们可能有一条消息,只有当用户是特定网络的一部分时才能访问(案例 3),或者无论网络如何,用户始终可以访问的消息(案例 1),或者一条消息在特定时刻处于给定网络中的所有用户都可以访问(案例 2)。

标签: mysql sql database-design


【解决方案1】:

您在问题中描述的内容称为多态关联。查看this article,其中描述了一些可能的建模方法。

虽然本文描述了如何以最一般的方式对多态关联进行建模,但我认为您的方法也不错,因为很可能不会有超过 3 种消息类型(对用户、对网络和对网络中的用户)

【讨论】:

  • 这是我的问题的完美文章。谢谢!
  • 酷,很高兴你发现它有帮助
【解决方案2】:

我见过的一种方法是在messages 中添加entity_identity_type,其中类型告诉您记录是指user 还是network(或稍后的其他类型) . This response 有一些处理此类案例的有趣示例。

【讨论】:

  • 在这种方法中是否可以定义外键约束?
  • 不使用 MySQL,因为外键引用过于死板,无法支持多个表。
【解决方案3】:

如果您在 3 个事物(A、B、C)之间存在多对多关系:

CREATE TABLE ABC (
    a_id ...,
    b_id ...,
    c_id ...,
    PRIMARY KEY(a_id, b_id, c_id),
    INDEX(b_id, c_id, a_id),
    INDEX(c_id, a_id, b_id)
) ENGINE=InnoDB;

索引让您可以从任何表到其他表。

但是...让我们看看你的一些SELECTs,然后再确定这是最好的。

【讨论】:

  • 如果我错了,请纠正我,但不是主键的所有列都必须不为空吗?如果是这样,我将如何处理我的问题中的关系 #1 和 #2?
  • 糟糕。计划 A:使用特定(非空)值而不是 NULL。 B计划:我的答案行不通。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 2014-03-29
  • 2021-10-06
  • 2018-11-22
  • 2011-01-31
  • 1970-01-01
相关资源
最近更新 更多