SQL 服务器中的唯一键是聚集索引还是非聚集索引?

Is Unique key Clustered or Non-Clustered Index in SQL Server?

我是 SQL 服务器的新手,在学习聚簇索引时,我感到很困惑!

唯一键是聚集索引还是非聚集索引? Unique key 只保存列中的唯一值,包括 null,所以根据这个概念,unique key 应该是聚集索引,对吧?但是当我阅读这篇文章时,我感到困惑 MSDN

When you create a UNIQUE constraint, a unique nonclustered index is created to enforce a UNIQUE constraint by default. You can specify a unique clustered index if a clustered index on the table does not already exist.

请帮助我更好地理解这个概念,谢谢。

在 SQL 服务器索引中有三种强制唯一性的方法。

  • 主键约束
  • 唯一约束
  • 唯一索引(不基于约束)

它们是聚簇的还是非聚簇的与是否使用这些方法中的任何一种将索引声明为唯一索引是正交的。

这三种方法都可以创建聚簇索引或非聚簇索引。

默认情况下,唯一约束和唯一索引将创建一个非聚集索引,如果你没有指定任何不同(如果不存在冲突的聚集索引,PK 将默认创建为 CLUSTERED)但是您可以为其中任何一个明确指定 CLUSTERED/NONCLUSTERED

示例语法为

CREATE TABLE T
(
X INT NOT NULL,
Y INT NOT NULL,
Z INT NOT NULL
);

ALTER TABLE T ADD PRIMARY KEY NONCLUSTERED(X);

--Unique constraint NONCLUSTERED would be the default anyway
ALTER TABLE T ADD UNIQUE NONCLUSTERED(Y); 

CREATE UNIQUE CLUSTERED INDEX ix ON T(Z);

DROP TABLE T;

对于未指定为唯一的索引 SQL 服务器将以任何方式默默地使它们唯一。对于聚簇索引,这是通过将唯一标识符附加到重复键来完成的。对于非聚集索引,行标识符(逻辑或物理)被添加到键以保证唯一性。

唯一索引既可以是聚簇索引也可以是非聚簇索引。 但是,如果您有可为空的列,则 NULL 值应该是唯一的(只有 1 行列为空)。 如果您想存储超过 1 个 NULL,您可以使用过滤器 "where columnName is not null".

创建索引

嗯,所有提供的答案都非常有帮助,但我仍然想添加一些详细的答案,这样我也会对其他人有所帮助

  1. 一个table只能包含一个聚簇索引,一个主键可以 是聚集/非聚集索引。
  2. Unique Key 也可以是 clustered/non-clustered 索引, 下面是一些例子

场景 1:主键将默认为聚簇索引

在这种情况下,我们将只创建主键,当我们检查在 table 上创建的索引类型时,我们会注意到它已自动在其上创建聚集索引。

USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO

场景二:主键定义为非聚集索引

在这种情况下,我们将显式定义主键为非聚集索引,并将其创建为非聚集索引。证明Primary Key可以是非聚集索引

USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY NONCLUSTERED,
Col1 INT NOT NULL)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO

场景 3:主键默认为非聚集索引,另一列定义为聚集索引

在这种情况下,我们将在另一列上创建聚簇索引,SQL服务器将自动创建一个主键作为非聚簇索引,因为在另一列上指定了聚簇索引。

-- Case 3 Primary Key Defaults to Non-clustered Index
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL UNIQUE CLUSTERED)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO

场景四:主键默认为聚簇索引,其他索引默认为非聚簇索引

在这种情况下,我们将在两个 table 上创建两个索引,但我们不会在列上指定索引的类型。当我们检查结果时,我们会注意到主键自动默认为聚集索引和另一列作为非聚集索引。

-- Case 4 Primary Key and Defaults
USE TempDB
GO
-- Create table
CREATE TABLE TestTable
(ID INT NOT NULL PRIMARY KEY,
Col1 INT NOT NULL UNIQUE)
GO
-- Check Indexes
SELECT OBJECT_NAME(OBJECT_ID) TableObject,
[name] IndexName,
[Type_Desc] FROM sys.indexes
WHERE OBJECT_NAME(OBJECT_ID) = 'TestTable'
GO
-- Clean up
DROP TABLE TestTable
GO

参考:the above details is been refrenced from this article