【问题标题】:SQL: Many to Many to a Many to Many... is this efficient?SQL:多对多对多对多……这效率高吗?
【发布时间】:2012-04-25 06:15:37
【问题描述】:

提前感谢您的意见。

我有 3 个对象:

  • 学校
  • 营地
  • 教练

具有以下关系:

  • 一个学校可以有多个营地。
  • 一所学校可以有多个教练。
  • 一个营地可以有多个学校。
  • 一个训练营可以有多个教练。
  • 一个教练可以拥有多个学校。
  • 一个教练可以有多个营地。

多对多,School_Camp,显然将学校链接到具有额外字段的营地,以标识营地的年份。但是一个营地可以有多个教练。

::School_Camp::

  • School_id
  • Camp_id
  • 日期

设置另一个多对多 School_Camp_Coach 链接到 School_Camp 和 Coach 表对我来说会更好吗?

::School_Camp_Coach::

  • School_Camp_id
  • Coach_id

如果这是更有效的方法...我应该给 School_Camp 一个可以快速引用的独立 id 列,而不是使用三个字段作为标识符吗?

::School_Camp::

  • 身份证*
  • School_id
  • Camp_id
  • 日期

只有一个多对多表 School_Camp_Coach 和 3 个外键会更好吗?

::School_Camp_Coach::

  • School_id
  • Camp_id
  • Coach_id
  • 日期

我预见到的唯一问题是,您将有多个外键条目,但日期不同。

再次感谢。

【问题讨论】:

  • 提前感谢时至少使用大写字母?
  • 在什么方面最有效?数据存储大小?检索或更新时间?查询复杂度?对于某些效率度量,这取决于您将如何处理数据。有时非规范化是值得的;其他时候不会。
  • 数据存储大小和查询复杂度是比较重要的因素。

标签: mysql sql


【解决方案1】:

这不是效率问题,而是正确性问题:您提出的两个选项没有模拟表中记录之间的相同关系。

数据库中的每条记录都意味着某种东西。如果连接表中记录的含义是“X 在学校 Z 的营地 Y 执教”,那么您应该选择选项 2;如果您希望独立于“X 为学校 Z 执教”和“学校 Z 跑营 Y”对“X 在 Y 营地执教”的含义进行建模,那么您应该选择选项 1。

在这两种情况下,您都应该为您的联结记录提供独立的主键,而不是依赖于 ID 的三向组合:当您实现对联结表应用更正的代码时,它将简化您的工作。

【讨论】:

  • 很好的答案......现在完全有意义。谢谢!
  • 描述关系的最佳方式:CoachX 是 SchoolY 的*当前教练。 CoachX 在 3 年前和今年为他们*当前的 SchoolY 举办了 CampZ。 *如果 CoachX 切换到另一个 SchoolY,并托管另一个 CampZ...CoachX 的前一个 CampZ 和 SchoolY 之间的关系保持不变。
【解决方案2】:

查看@Ted Hopp 的评论。

鉴于数据(学校营地每分钟不会发生多次),我认为更新时间不如检索时间优先。如果这是真的,我会选择你的最后一个选项,3 个外键。

这将是star schema 的示例。

【讨论】:

  • 我没有考虑更新或检索时间。我仍在尝试设计数据库...感谢您让我深入了解数据库设计中应包含的另一个因素。
【解决方案3】:

在我看来,Coach 实体应该具有我通常称之为basket 的东西,它可以在多对多关系中与其他实体链接。我的意思是这样的:

# The coach model
CREATE TABLE coach(
    id INT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY(id),
    name VARCHAR(20),
    capacity INT
) ENGINE=InnoDB;

# The coach data - who is using the coaches
CREATE TABLE coach_basket(
    coach_id INT,
    FOREIGN KEY(coach_id) REFERENCES coach(id),
    entity_id INT, /* the school or camp id */
    entity_type ENUM("School","Camp"),
    fromdate DATETIME,
    todate DATETIME
) ENGINE=InnoDB;

所以现在您可以跟踪所有教练的使用情况,只需输入 entity_id(学校或营地 ID),以及他们每次使用教练的日期和时间。

您需要一个类似类型的表来存储连接的学校和营地,它可以如下所示:

# Store school-camp connections
CREATE TABLE connections(
    school_id INT,
    FOREIGN KEY(school_id) REFERENCES school(id),
    camp_id INT,
    FOREIGN KEY(camp_id) REFERENCES camp(id)
) ENGINE=InnoDB;

非常简单,只需保存学校和营地 ID,因此如果您查询一个 school_id,您会得到许多与该学校相关联的营地,反之亦然。

剩下的就是你的schoolcamp 表,它们是模型(就像顶部的教练表)。

【讨论】:

  • 我以前从未见过这个篮子。有趣的方法。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 2014-08-04
  • 1970-01-01
  • 2012-05-30
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多