数据库设计中的多对多关系

时间:2010-10-28 00:42:21

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

我正在构建一个利用大量多对多关系的数据库。例如,我有零件和机器项目,每个零件进入许多机器,每台机器有很多零件。此数据库的目的是能够输入部件列表并返回仅由该列表中的部件组成的机器列表,反之亦然。我是数据库设计的新手,所以我目前正在使用转换表建模这种关系,例如:

创建台式机器( machine_id号码, machine_name char(30) )

创建表部分( part_id号码, part_name char(30) )

创建表关系( part_id号码, machine_id号码 )

这似乎是一种非常丑陋和天真的方式来建立这种关系。有没有更好的方法来做到这一点,比如以某种方式在各自的表下的单列中存储和更新列表或者我还没想过的更好的东西?我正试图找到一种方法来最大限度地减少查询时间和后处理强度。

感谢。

6 个答案:

答案 0 :(得分:8)

欢迎使用关系数据库。不,没有更好的方法。我建议稍微更好地命名你的桌子; Machine,Part,Machine_Part或类似的东西,因为你最终可能会得到一堆这类表。

后期处理实际上不是问题,使用SQL中的简单INNER JOIN或使用ORM来处理这些关系相当容易。数据库旨在应对这种情况。

答案 1 :(得分:4)

编辑以提高清晰度

实际上有更好的方法可以在真正的关系数据库中进行设计(已经完成了数千次)。

该结构称为物料清单结构,并且在关系模型之前就存在了。当然,我会给你关系版本。这是高性能并且没有处理限制,例如。您可以使用简单的存储过程生成树结构(BoM)报告,该过程称为递归调用。

在我们追逐之前需要了解的一些事情。

  1. 从你的desc,机器实际上是Assemblies(部件)。这些程序集用于(更高级别)程序集,依此类推。因此,让我们将“关系”重命名为Assembly。

  2. 您的零件和机器表尚未标准化。如果仔细检查它们,您会发现许多相同的列(显示PartId :: MachineId,PartName :: MachineName)。实际上除了最低的机器部件和最高的机器部件之外,所有介入机器(包含部件)实际上也是(更高级别)机器中的零件。所以你有可怕的数据重复。这是一个很大的Normaalisation错误。这会扼杀性能。生成的更新异常将导致数据完整性问题。在你的其他问题出现之前很久,这些问题就会浮出水面 。
    所以必须通过标准化的普通过程来纠正:Part和Machine成为一个表:Part。部件可以是组件(组件)的事实基于使用的上下文;零件可以是组件(在组件中)的事实同样基于上下文。作为一个坐在架子上的单元,您必须保留零件和机器的库存,每个零件都是零件。库存控制栏位于Part;上下文列位于Assembly中。

  3. 多对多关系(在逻辑上它们是关系,而不是表)在物理层面上实现为关联表,没有办法解决这个问题。你已经有了。你将要看到的可能看起来不同,但事实并非如此。

  4. 你从我这里得到的任何东西都是5NF;零数据重复;零更新异常。这在多个生产基地的生产中运行。碰巧我在Advanced课程中使用了所需的结构作为教程的一部分,所以你可以查阅它。随意提出任何与理解或其他相关的问题。它正是在教程中,因为许多开发人员不了解结构或如何导航它。请注意非常严格(经过测试和测试)的命名约定。

    点击部分汇编(您可以忽略模型的其余部分,但我也很乐意回答有关它的问题)。方法和图表符号都是IDEF1X(它是RM的“严格”再现)。

    Part-Assembly-Component Example

    是的,数据完整性得到维护,Assembly⇢Component搜索服务100%(允许覆盖查询),来自程序集主键索引(也就是说,它们已经非常高优化,我不需要让他们这些或那些一些供应商,以获得更快的速度)。第二个唯一索引为Component⇢Assembly搜索提供100%。

    享受。

答案 2 :(得分:3)

这不是天真的,这是ER模型的正确方法。用关系分隔实体,经典的设计模式。不担心查询/加入开销,RDBMS针对此进行了优化,可以飞过这些连接查询。

您还可以使关系表具有(part_id,machine_id)作为复合主键。更好的是,将它们创建为索引的有组织的表,并避免表数据的任何(可忽略的)开销。

答案 3 :(得分:3)

简短的回答:你朝着正确的方向前进。这是创建多对多关系的教科书方式。

然而,“机器”可能只是“部分”的一个特例,即在某种意义上你认为是“完整的东西”或可交付物品的一部分。

大多数人这样做会创建一个层次结构。你有:

part(part_id, description, ... maybe other data like size and weight, etc ...)
assembly(parent_part_id, child_part_id)

然后顶层部件可以有许多组件,每个组件都可以有其他组件等。这样做的好处是,当一个组件用于多个最终产品时,您只需要描述突破一次。例如,我曾经在一家制造洗碗机的公司工作。在out part表中,我们有一个记录,比如Motor motor 29B。该电机将具有许多组件 - 外壳,转子,一些定子,电线束等。但是相同的电机可以用在几种不同型号的洗碗机中。您不希望必须为每个使用的洗碗机重新给出电机的整个零件清单。这不仅是某人输入的痛苦,而且如果你做出改变,你必须确保在其使用的任何地方改变它。因此,您只需为电机提供一次突破,然后将电机作为一个单元引用到所有更高级别的组件中。

是的,有些部分是“最终的”,也就是说,它们不会进行更高级别的装配。但是你不需要一个不同的表。这只意味着对于这个特定的部分,没有汇编记录,这是孩子。

零件是零件。把它们放在一张桌子里。

某些数据库引擎,例如Oracle,有命令追逐这样的层次结构。如果你没有,你必须在代码中完成。但它并不那么艰难。人们一直这样做。

答案 4 :(得分:2)

这是规范化数据 - 将part记录的任意组合存储到machine记录的最具扩展性的方法。

  

我正试图找到一种方法来最大限度地减少查询时间和后处理强度。

在实际遇到问题时处理问题 - 否则就是过早优化。

答案 5 :(得分:2)

一种明确的思考方式:逻辑与物理

两个实体之间的逻辑多对多关系(称为A和B)具有三个表的物理实现(称为A,B和C)。此实现涉及从A到C的物理一对多关系。另一个从B到C.表C被称为“连接表”或“连接表”