SQL Server中的唯一键是聚集索引还是非聚集索引?

12

我是SQL Server的新手,在学习聚集索引时感到困惑!

唯一键是聚集索引还是非聚集索引?唯一键仅在列中包括null的情况下持有唯一值,因此根据这个概念,唯一键应该是聚集索引,对吗?但是当我阅读MSDN的文章时感到困惑。

创建唯一约束时,默认会创建一个唯一的非聚集索引来强制执行唯一约束。如果表上不存在聚集索引,则可以指定唯一的聚集索引。

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


2
除非你在“创建索引”时使用“clustered”选项显式定义,否则“unique”键不会被聚集。 - Gordon Linoff
这个问题在 https://dev59.com/yXM_5IYBdhLWcg3wvFzJ 和 https://msdn.microsoft.com/en-CA/library/ms190457.aspx 中有更好的解释。 - yelxe
3个回答

11

在SQL Server索引中,有三种实现唯一性的方法。

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

无论它们是聚集索引还是非聚集索引,都与使用这些方法声明索引是否唯一无关。

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

默认情况下,如果您没有指定任何不同的选项(并且如果不存在冲突的聚集索引,则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 Server 将会默默地将它们变为唯一。对于聚集索引,这是通过在重复键后附加一个唯一标识符来完成的。对于非聚集索引,则会添加行标识符(逻辑或物理)到键中以保证唯一性。


你能给我一些关于如何创建带有聚集/非聚集索引的主键和唯一键的参考资料吗? 如果主键可以是非聚集索引,那么这是否意味着我们可以在一个表中拥有多个主键?我们该如何做到这一点?请提供一些详细信息,我越是学习这个东西,就越感到困惑。 谢谢。 - Lijin Durairaj
1
@LijinJohn - 每个表只能有一个主键,每个表只能有一个聚集索引,但这两者不必相同。 - Martin Smith
我从 MSDN 博客中了解到的是,唯一键和唯一约束之间在数据相关方面没有区别,我是对的吗? - Lijin Durairaj
1
@LijinJohn - 没有区别,除了灵活性。唯一索引可以定义包含列,而基于约束的索引则不行。 - Martin Smith
非常感谢您的支持 :) - Lijin Durairaj

2

唯一索引可以是聚集或非聚集的。 但如果您有可空列,则 NULL 值应该是唯一的(只有一个列为 null 的行)。 如果您想存储多个 NULL,可以使用过滤器“where columnName is not null”创建索引。


2

所有提供的答案都非常有帮助,但我想添加一些详细的答案,以便对其他人也有所帮助。

  1. 一个表只能包含一个聚集索引,而主键可以是聚集/非聚集索引。
  2. 唯一键也可以是聚集/非聚集索引,以下是一些示例

情况1:主键默认为聚集索引

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

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

情境二:将主键定义为非聚集索引

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

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

情境三: 当另一列被定义为聚集索引时,主键默认为非聚集索引

在这种情况下,我们将在另一列上创建聚集索引,SQL Server会自动创建一个作为非聚集索引的主键,因为已经在另一列上指定了聚集索引。

-- 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:主键默认为聚集索引,其他索引默认为非聚集索引

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

-- 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

参考:上述内容参考自该文章

以下是关于IT技术的翻译:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接