【问题标题】:Using two similar tables or flags for many-to-many relationship为多对多关系使用两个相似的表或标志
【发布时间】:2016-09-13 13:25:28
【问题描述】:

我最近遇到了一个项目,我想将一些应用程序添加到数据库中。每个应用程序都有以 1:1、1:n 或 n:m 关系出现的附加信息。虽然我知道如何存储此类关系,但我在每个应用程序的开发者/发布者方面遇到了一些麻烦。

情况:

  • 数千个应用程序
  • 每个应用都有自己的 id
  • 数千家公司
  • 每个公司(开发者/发布者)都有自己的 ID
  • 每个应用可以有 0、1 或多个开发者
  • 每个应用可以有 0、1 或多个发布者
  • 每个开发者可以拥有 1 个或多个应用程序
  • 每个发布者可以有 1 个或多个应用程序

很明显,这是一个多对多关系,因此需要一个联结表。不幸的是,至少有两个可行的选择。

公司

CREATE TABLE `company` (
 `id` smallint(5) UNSIGNED NOT NULL,
 `name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

(我在这张表中合并了开发者和发布者,因为开发者也可以是发布者,反之亦然。我认为这比在两个单独的表中冗余更好,不是吗?)


选项 1:

第一个选项是创建两个单独的表。

app_developer

CREATE TABLE `app_developer` (
 `id` mediumint(8) UNSIGNED NOT NULL,
 `app_id` mediumint(8) UNSIGNED NOT NULL,
 `company_id` mediumint(8) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

app_publisher

CREATE TABLE `app_publisher` (
 `id` mediumint(8) UNSIGNED NOT NULL,
 `app_id` mediumint(8) UNSIGNED NOT NULL,
 `company_id` mediumint(8) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

选项 2:

第二个选项是创建一个表并为每个应用程序/公司组合添加标志 (0/1)。

CREATE TABLE `app_company_rel` (
 `id` mediumint(8) UNSIGNED NOT NULL,
 `app_id` mediumint(8) UNSIGNED NOT NULL,
 `company_id` mediumint(8) UNSIGNED NOT NULL,
 `developer` tinyint(1) UNSIGNED NOT NULL,
 `publisher` tinyint(1) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我不知道将来是否需要搜索来自特定开发者/发布者的所有应用程序,或者这只是没有进一步目的的附加信息。

哪个选项会更好(在一致性、冗余、性能方面)或者没有显着差异?

【问题讨论】:

    标签: mysql database-design many-to-many


    【解决方案1】:



    您的第一个选择将非常有效。存储在两个不同的表中实际上是好的。创建两个表并使用 app_id 作为外键。存储在两个不同的表中使数据非常清晰,数据检索也将非常容易和快捷。有任何疑问请告诉我,会为您解释清楚

    【讨论】:

      【解决方案2】:

      选项 3:与 #2 类似,但对于 dev 和 pub 使用 ENUMSET

      我会考虑选项 1 或选项 3。但我会包含一个简单的多对多映射表的id;它会减慢速度。

      More discussion 以及如何编写最佳多对多表的技巧。

      【讨论】:

      • enum 会比tinyint(1) 更好吗?由于应用程序/公司的每个组合都可以是 1/0、0/1 或 1/1,因此我认为 tinyint(1) 表示 true/false 在这里更适合。但是,我同意删除 id,因为这不是必需的 - 我只是忘记将其从架构中删除。
      • ENUM('developer', 'publisher', ...) - 也许会有第三类?
      • 别忘了添加PRIMARY KEY 和二级索引。
      • 但如果一家公司同时是开发者和发布者,ENUM('developer', 'publisher', ...) 将不起作用。我想我更喜欢选项#1然后使用PRIMARY KEY ('app_id','company_id'), INDEX ('company_id','app_id')。还是我错过了什么?
      • 然后使用SET 而不是ENUM。无论如何,这只是一个“建议”,而不是“强烈推荐”。
      【解决方案3】:

      您的第二个选项是正确的。但这不仅建立了公司和项目之间的关系,还建立了关系的类型——开发者或发布者。

      create table ProjCompany(
          ProjID    int not null references Projects( ID ),
          CompanyID int not null references Company( ID ),
          TypeID    char( 1 ) not null references Types( ID ), -- 'D' or 'P'
          constraint OK_ProjCompany primary key( ProjID, CompanyID, TypeID )
      );
      

      一个项目只能将每家公司列为开发者一次,但同一家公司也可以列为发布者。一家公司可以是任意数量项目的开发者和/或发布者。

      如果任何表需要对特定项目的特定开发人员的 FK 引用,它将使用项目 ID、公司 ID 和开发人员标志来引用此表。如果该公司未被定义为该项目的开发人员,则该引用将被拒绝。

      此外,我会推荐一个显示每个项目及其开发人员的视图,以及一个显示每个项目及其发布者的视图。这对于仅与开发人员或仅与发布者合作的部分代码会派上用场。

      【讨论】:

        猜你喜欢
        • 2018-04-04
        • 1970-01-01
        • 1970-01-01
        • 2015-03-07
        • 1970-01-01
        • 2016-06-22
        • 2018-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多