SQL Server中的唯一键群集或非群集索引?

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

我刚接触到SQL Server,在学习集群索引时,我很困惑!

唯一键是聚集索引还是非聚集索引?unique key只包含列中的唯一值,包括空值,所以根据这个概念,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 Server索引中有三种强制唯一性的方法。

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

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

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

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

示例语法是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 Server将以任何方式静默地使其唯一。对于聚集索引,这是通过将uniquefier附加到重复的键来完成的。对于非聚集索引,行标识符(逻辑或物理)将添加到键以确保唯一性。


好吧,所有提供的答案都很有帮助,但我还是想添加一些详细的答案,以便我也能帮助其他人。

  • 表只能包含一个聚集索引,主键可以是聚集索引/非聚集索引。
  • 唯一键也可以是聚集/非聚集索引,下面是一些例子
  • 场景1:主键将默认为聚集索引

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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 Server将自动创建主键作为非聚集索引,因为在另一列上指定了聚集索引。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    -- 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

    场景4:主键默认为聚集索引,其他索引默认为非聚集索引

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    -- 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

    参考文献:以上细节已从本文中引用。


    唯一索引可以是聚集索引,也可以是非聚集索引。但是,如果有可以为空的列,则空值应该是唯一的(只有1行的列是空的)。如果要存储多于1个空值,可以使用筛选器"其中columnname不为空"创建索引。