T-SQL 聚集外键

Bre*_*ias 5 t-sql sql-server performance foreign-keys

“创建表”语法显然不允许我指定聚集外键约束。换句话说,这是非法的:

--keyword CLUSTERED must be removed before this will execute...
CREATE TABLE [Content](
    [ID] [int] NOT NULL CONSTRAINT PK_Content_ID PRIMARY KEY,
    ContentDefID int NOT NULL CONSTRAINT FK_Plugin_ContentDef FOREIGN KEY CLUSTERED REFERENCES ContentDef(ID)
    )
GO
Run Code Online (Sandbox Code Playgroud)

但我不明白为什么这是非法的。ISTM 认为聚集外键将有助于分页查找的性能。换句话说,“给我父 ID 20 的子项 80 到 140”。

这有什么道理吗?

更新

根据 Oded 和 Tvanfosson 的反馈,我发现以下方法有效:

CREATE TABLE [Content](
    [ID] [int] NOT NULL CONSTRAINT PK_Content_ID PRIMARY KEY,
    ContentDefID int NOT NULL UNIQUE CLUSTERED CONSTRAINT FK_ContentDefContent FOREIGN KEY REFERENCES ContentDef(ID)
    )
GO
Run Code Online (Sandbox Code Playgroud)

但上述造成的问题多于其解决的问题。首先,“唯一”外键迫使我的关系成为一对一,这是我不想要的。其次,这之所以有效,是因为它代表了两个单独约束的创建,而不是单个聚集外键。

但这次调查让我更接近我的答案。显然,聚集索引必须是唯一的,如此处所述。引用:

如果聚集索引不是唯一索引,SQL Server 会通过添加称为唯一符的内部生成的值来使任何重复键唯一

特别是,我认为这个答案涵盖了它。

ype*_*eᵀᴹ 4

正如其他人所解释的,聚集索引不必是主键,但它必须是唯一的,或者 SQL-Server 向其添加一个(未显示)UNIQUIFIER列。

为了避免这种情况,您可以通过将主键列显式添加到聚集索引来使聚集索引唯一,如下所示。然后,该索引将可供外键约束使用(以及查询,例如连接两个表)。

请注意,正如 @Martin Smith 所解释的,CONSTRAINT和的概念INDEX是不同的。不同的 DBMS 以不同的方式实现这些。SQL-Server 会自动为某些约束创建索引,但不会为外键约束创建索引。但建议有一个约束可以使用的索引(在引用表中删除或更新时):

CREATE TABLE Content(
    ID int NOT NULL,
    ContentDefID int NOT NULL,
    CONSTRAINT PK_Content_ID 
      PRIMARY KEY NONCLUSTERED (ID),
    CONSTRAINT CI_Content
      UNIQUE CLUSTERED (ContentDefID, ID),
    CONSTRAINT FK_Plugin_ContentDef 
      FOREIGN KEY (ContentDefID) REFERENCES ContentDef(ID)
) ;
Run Code Online (Sandbox Code Playgroud)