SQL Server 2008上的唯一键与唯一索引

时间:2012-04-21 22:55:56

标签: sql sql-server sql-server-2008 tsql sql-server-2008-r2

我有一个名为countries的表,我通过在SQL Server 2008 R2上创建“唯一键”类型的“索引/键”来将country_name列定义为唯一。

但我有以下问题:

  1. 会创建“唯一键”类型的“索引/键”,会自动在此列上创建非聚集索引吗?
  2. 如果我将类型从“唯一键”更改为“索引”并且我将IsUnique值保持为“是”,那么会有任何差异吗?
  3. 那么为什么有两个选项“Unique Key”和“Index”我认为两者是相同的?

7 个答案:

答案 0 :(得分:65)

唯一约束作为唯一索引在幕后实现,因此指定它并不重要。我倾向于简单地实现它:

ALTER TABLE dbo.foo ADD CONSTRAINT UQ_bar UNIQUE(bar);

有些人会创建一个唯一的索引,例如

CREATE UNIQUE INDEX IX_UQ_Bar ON dbo.foo(bar);

不同之处在于意图 - 如果要创建约束以强制执行唯一性/业务规则,则创建约束,如果这样做是为了帮助查询性能,则创建唯一索引可能更合乎逻辑。同样,在幕后它是相同的实现,但你走的路可能有助于记录你的意图。

我认为有多种选择可以遵循以前的Sybase功能以及遵守ANSI标准(即使唯一约束不符合标准100%,因为它们只允许一个NULL值 - 一个唯一的另一方面,索引可以通过在SQL Server 2008及更高版本上添加WHERE子句(WHERE col IS NOT NULL)来解决此问题。

答案 1 :(得分:13)

还有一点需要注意的是,如果你创建索引,你可以指定包含的列,如果有一些按country_name搜索,这可以帮助你的SQL代码更快地工作。

CREATE UNIQUE NONCLUSTERED INDEX IX_UQ_Bar
ON dbo.foo (
    bar
)
INCLUDE (foo_other_column)
GO

SELECT foo_other_column FROM Foo WHERE bar = 'test'

SQL Server将在索引本身中存储“foo_other_column”。在唯一约束的情况下,它将首先找到'test'的索引,然后将在foo表中搜索行,并且只在那里搜索“foo_other_column”。

答案 2 :(得分:1)

唯一索引或唯一约束之间没有区别,也没有性能差异。但是,在创建方面存在一些差异,其中某些索引创建选项不适用于唯一约束。

答案 3 :(得分:0)

如果您使用SqlMetal.exe输出DBML或LinqToSql实体:

  • 如果外键使用唯一键,则会按预期获得关联。
  • 如果外键使用唯一索引,则不会显示。

原因在于SqlMetal的实现。它查询数据库信息模式,特别是关键列使用情况。这里表示唯一键,但不是唯一索引。

SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME, ORDINAL_POSITION
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE;

答案 4 :(得分:0)

除了上面的优秀答案,我在这里加2美分。

唯一键是一个约束,它使用唯一索引来强制执行。正如主键通常由集群唯一索引强制执行一样。 从逻辑上讲,约束和索引是两回事。但是在RDBMS中,约束可以通过索引实际实现。

如果在sql server中创建了一个具有唯一约束的表,您将看到约束对象一个唯一索引

create table dbo.t (id  int constraint my_unique_constraint unique (id));

select [Constraint]=name from sys.key_constraints 
where parent_object_id = object_id('dbo.t');

select name, index_id, type_desc from sys.indexes
where object_id = object_id('dbo.t')
and index_id > 0;

我们将得到以下内容(约束和索引)

enter image description here

但是,如果我们不创建约束,而只是创建一个唯一索引,如下所示

create table dbo.t2 (id int );
create unique index my_unique_constraint on dbo.t2 (id);

select [Constraint]=name from sys.key_constraints 
where parent_object_id = object_id('dbo.t2');

select name, index_id, type_desc from sys.indexes
where object_id = object_id('dbo.t2')
and index_id > 0

您将看到没有创建约束对象(仅创建索引)。

enter image description here

从“理论”的角度来看,在SQL Server中,约束是具有object_id值且受模式约束的对象,而索引不是对象且没有object_id值且没有架构相关。

答案 5 :(得分:0)

实施唯一性的第三个选择是使用过滤的唯一索引来允许可空的唯一索引。
不适用于唯一约束。
例如,假设您有一列只想允许唯一值,
 但仍然希望在不存在多个NULL值时支持它们。
过滤后的唯一索引将起作用:

CREATE UNIQUE NONCLUSTERED INDEX [UF_Employee_UserID] ON [dbo].[Employee]
(
    [UserID] ASC--Not all Employees have a UserID to log into the System.
)
WHERE ([UserID] IS NOT NULL)--Enforce Uniqueness when not null.

现在,使用GUI编辑表时,仍然无法在SSMS中创建过滤索引。
但是,如果要通过GUI而不是手动创建索引(如上),则可以关闭所有打开的表设计器,然后在对象资源管理器中打开索引本身的属性。

答案 6 :(得分:0)

最重要的一点是,假设您想通过保持唯一性来使列值保持为空,而对于唯一键约束则无法做到,但是通过唯一键索引,您可以通过保持唯一性来使列值保持为空。 因此,如果您需要具有可以为Null的类型的唯一列,则需要Unique Index;否则,如果您需要不可为null的列,则需要唯一键约束。