Database design 当复合键存在时,主键中不包括唯一ID字段

Database design 当复合键存在时,主键中不包括唯一ID字段,database-design,indexing,sql-server-2008-r2,primary-key,Database Design,Indexing,Sql Server 2008 R2,Primary Key,我正在尝试在SQLServer2008R2中构建一个数据库,允许用户将自己的子类型放入类别中。我有一个父表,其中包含预设的类别名称(由我定义) 我面临的问题是什么是处理主键和唯一约束以及外键引用的最佳方法。索引是其中的核心,因为我预计子表(我们称之为CategoryTypes)将随着时间的推移变得相当大,并且需要能够有效地允许基于父表(Categories)读取数据。如果表格的布局如下所示,我是否需要预测任何问题 我担心的是,CategoryTypes表中的IDENTITY列需要维护一个唯一的计

我正在尝试在SQLServer2008R2中构建一个数据库,允许用户将自己的子类型放入类别中。我有一个父表,其中包含预设的类别名称(由我定义)

我面临的问题是什么是处理
主键
唯一
约束以及外键引用的最佳方法。索引是其中的核心,因为我预计子表(我们称之为
CategoryTypes
)将随着时间的推移变得相当大,并且需要能够有效地允许基于父表(
Categories
)读取数据。如果表格的布局如下所示,我是否需要预测任何问题

我担心的是,
CategoryTypes
表中的
IDENTITY
列需要维护一个唯一的计数。我之所以包含此字段,是为了在应用程序中的层之间传递数据时允许更简单的引用。通过传递整数对整数/字符串对。这些表中的数据将保留在数据库的每一层,以节省带宽。从数据库的角度来看,一旦部署,下面的布局是否会带来任何重大挑战

为了简化,当存在复合密钥时,使用主键中不包含的唯一ID字段(
标识
)是否存在问题?见下表布局:

父表:

CREATE TABLE schema.Categories
(
  Id TINYINT PRIMARY KEY NOT NULL,
  Name VARCHAR(100) NOT NULL,
)
子表(用户随时间插入的数据):


你所描述的听起来有点像继承结构。据我所知,我已经创建了一个示例数据集。你能证实这是你的意图吗

如果是,那么这应该可以正常工作,我不明白为什么不将CategoryType.Id设置为主键?如果它不是你的PK,也不是在其他地方被引用为FK,那么我看不出它有什么意义。我个人认为你节省的带宽不够多,可能只需要按类别ID和名称请求数据。事实上,没有PK通常是继承结构的表示方式()

如果您必须保持设置的方式,我个人建议将Id设置为PK,并在CategoryId/Name上设置唯一的约束

不过那只是我的两分钱

Category
----
Id|Name
1 |Food
2 |Drink

CategoryType
----
Id|CategoryId|Name
1 |2         |Water
2 |2         |Orange Juice
更新答案(直接解决性能问题)

首先,我建议如果这不是一个问题的话,就不要完全太担心它。这是我们许多人都会遇到的一个常见问题,它使不需要它的东西变得过于复杂。这是我书中的一部分

然而,如果你死心塌地地想按照你解释的方式提前解决这个问题,那么我还有一些想法:

  • 创建PK作为Id,但要使其非聚集
  • < LI>创建CythyYID上的聚集索引,并考虑使用上面的非聚集索引上的一个。
  • 只有在使用CategoryId而不是CategoryType.Id进行查询时,才需要执行上述操作
  • 但是,在创建密钥时需要考虑的一点(甚至可以从
    INCLUDE
    文章中获得)
最终,我认为你所做的一切都会很好,但是PK不需要集群,所以我肯定会将PK移动到Id字段。如果要在CategoryId或CategoryId/Name上创建集群,或者按照我的建议尝试使用INCLUDE,这是您的选择。这实际上取决于表的使用方式,因此比较执行计划可能会有所帮助


希望这能有所帮助:)

PS-我还想补充一点,子表“CategoryTypes”中的Id将通过外键关系被其他表引用。。。所以这是必要的。我愿意接受任何在表设计中解决如此复杂问题的最佳实践。请注意,在集群表中,二级索引是昂贵的。如果您真的不需要代理项键
{Id}
,那么就不要使用它,只使用自然键
{CategoryId,Name}
。如果您想要两个键,请使用基于堆的表(即,
主键非聚集的
)。Branko,我知道额外的开销,但感谢您在本文中重申这一点。我面临的挑战是我知道我需要引用代理Id(外键)。我想你可以做一个复合外键。。。但我对这个不太熟悉。代理似乎让事情变得容易多了。也就是说,我可以从消除“集群式”索引开始,转而使用“非集群式”,正如您和Justin所建议的那样。如果以后需要性能,我可以在获得一些生产数据后解决。在CRUD中,聚集索引有助于“读取”,但会增加开销。此外,我将在存储过程方面做很多工作。代理将使编写这些过程变得更简单。除非您或Justin觉得有更多的理由探索复合外键,否则我将按照建议使用堆表。外键可以引用任何键,无论是主键还是备用键、代理键还是自然键、单字段键还是复合键。我只是想警告您,如果使用第二个键,这意味着一个二级索引,而聚集表中的任何二级索引(包括键下的索引)都会受到一定的惩罚。在现有的自然密钥之外引入代理密钥是有正当理由的;这在集群环境中可能带来的复杂性只是反对它的原因之一。Justin,回答你的问题“这是一个继承结构吗”-是的。你所举的例子与我试图做的完全相似。您对使Id成为PK的评论是我在SQL中的当前结构所实现的。我将其反向发布的原因是索引(例如,当您有一百万个CategoryTypes时,基于复合关系的聚集索引是否会有好处?我同意,PK
Category
----
Id|Name
1 |Food
2 |Drink

CategoryType
----
Id|CategoryId|Name
1 |2         |Water
2 |2         |Orange Juice
Index maintenance may increase the time that it takes to perform modifications
, inserts, updates, or deletes, to the underlying table or indexed view.