【问题标题】:Primary Key / Clustered key for Junction Tables连接表的主键/聚集键
【发布时间】:2011-01-25 12:32:23
【问题描述】:

假设我们有一个 Product 表、一个 Order 表和一个(联结表)ProductOrder。

ProductOrder 将有一个 ProductID 和一个 OrderID。
在我们的大多数系统中,这些表还有一个称为 ID 的自动编号列。

放置主键(以及聚集键)的最佳做法是什么?

  • 我是否应该保留 ID 字段的主键并为外键对(ProductID 和 OrderID)创建非聚集索引

  • 或者我应该把外键对(ProductID和OrderID)的主键放在ID列上(如果有必要的话)

  • 或者……(你们中的一个聪明的评论:))

【问题讨论】:

    标签: sql clustered-index junction-table


    【解决方案1】:

    我知道这些话可能会让你畏缩,但“这取决于。”

    您很可能希望订单基于 ProductID 和/或 OrderId 而不是自动编号(代理)列,因为自动编号在您的数据库中没有自然意义。您可能希望按与父表相同的字段对连接表进行排序。

    1. 首先了解为什么以及如何使用代理键 ID 首先;这通常会决定你如何索引它。一世 假设您正在使用代理键,因为您正在使用一些 与单列键配合良好的框架。如果没有 具体的设计原因,然后对于连接表,我会简化 问题,只需删除自动编号 ID,如果它没有带来其他 益处。主键变为 (ProductID, OrderID)。如果不, 您至少需要确保您在 (ProductID, OrderID) 元组是唯一的以保持数据完整性。

    2. 聚集索引适用于顺序扫描/连接,当 查询需要与索引的排序顺序相同的结果。 因此,请查看您的访问模式,找出您使用哪些键 将进行顺序的多行选择/扫描,以及通过哪个 键,您将进行随机、单独的行访问,并创建 您将扫描最多的键上的聚集索引,以及非聚集索引 您将用于随机访问的密钥上的密钥索引。你必须 选择一个或另一个,因为你不能同时聚类。

    注意:如果您有相互冲突的要求,有一种技术(“技巧”)可能会有所帮助。如果查询中的所有列都在索引中找到,则该索引是数据库引擎用来满足查询要求的候选表。您可以使用这一事实以多个顺序存储数据,即使它们相互冲突。请注意向索引添加更多字段的利弊,并在了解将要处理的查询的性质和频率后做出有意识的决定。

    【讨论】:

      【解决方案2】:

      正确且唯一的答案是:

      • 主键是('orderid' , 'productid')
      • ('productid' , 'orderid') 上的另一个索引
      • 两者都可以集群,但默认是PK

      因为:

      • 您不需要单独在 orderidproductid 上建立索引:优化器将使用其中一个索引
      • 您很可能会“两种”方式使用表格
      • 您不需要代理键,因为您已经在链接表中拥有了代理键。所以第三列会浪费空间。

      【讨论】:

      • 我确实读到将聚集索引中的列添加到非聚集索引中被认为是不好的做法:聚集索引总是添加到非聚集索引中。因此索引 'productid' + 'orderid' 没有意义?
      • @Zyphrax:列顺序使其成为完全不同的索引
      【解决方案3】:

      我的偏好一直是为主键创建自动编号。然后我在两个外键上创建一个唯一索引,这样它们就不会重复。

      我这样做的原因是因为我对数据进行规范化的次数越多,我必须在连接中使用的键就越多。我最终设计出了六到七层深的设计,如果我使用从一层流向另一层的键,我可能会在连接中得到 n^2 个键。

      尝试说服我的 SQL 开发人员将所有这些用于单个查询,他们会真的很喜欢我

      我保持简单。

      【讨论】:

      • 当链接表已经使用自动编号列时,为什么要添加第三列?无意义
      • 不要让开发人员仅仅因为他们懒得写连接或视图而决定设计。如前所述,链接表没有自动编号列,因为它们是不应该显而易见的实现细节。您不应该单独查询或公开链接表,它始终是连接的一部分。考虑写一个视图,让开发者使用视图,链接表永远不明显。
      • @gbn 和@mrjoltcola:大多数连接表都有附加属性。 OrderItem 表可能具有 ItemPrice,因此对查找 Items 表的更改不会将订单价格从 Quoting 更改为 Shipment。所以我为这个表创建了一个 OrderItemId。当它连接到 ShippingLocationItems 表时,我有一个 2 键连接而不是 1 键连接。当我使用 DeliverConfirmatioForItems 进行跟踪时,我再次拥有一个 1 列外键,而不是 8 个或更多列,用于运输 loc 详细信息、交付和签名机制。对所有连接表执行此操作并保持统一。
      【解决方案4】:

      这似乎适用于将添加许多订单的动态系统。因此,聚集索引应该在您的自动编号列上。

      您可以将索引作为主键,并在这对列上放置另一个唯一索引。或者,您可以将这对列设置为主键(但非集群键)。

      使用主键或唯一索引键由您决定。但我会确保集群用于您的自动编号列。

      【讨论】:

      • 我不同意。自动编号列没有任何意义,除了“这是创建记录的顺序”。集群将按集群键对行进行排序。 “按创建顺序”自动编号通常不是您查询表的顺序。最有可能的是,此表将用于使用 ProductID 和 OrderID 对产品和订单进行连接。我会为排序而集群,因此集群键与最常见查询的驱动表的顺序相同,否则您将浪费集群索引。
      • 我想问题归结为这张桌子有多忙?如果有很多插入,那么您可能会进入必须在每次插入时重新构建表的状态。这会减慢系统速度,尤其是在大桌子的情况下。使用自动编号上的聚集索引,这不会发生。另一个索引可以设置填充以提供额外空间以避免重组。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-20
      • 2015-10-23
      • 1970-01-01
      • 2010-10-09
      • 2014-07-30
      • 1970-01-01
      • 2011-08-21
      相关资源
      最近更新 更多