什么时候应该使用唯一约束而不是唯一索引?


194

当我希望一列具有不同的值时,我可以使用约束

create table t1(
id int primary key,
code varchar(10) unique NULL
);
go

或者我可以使用唯一索引

create table t2(
id int primary key,
code varchar(10) NULL
);
go

create unique index I_t2 on t2(code);

具有唯一约束的列似乎是唯一索引的良好候选者。

是否存在使用唯一约束而不使用唯一索引的已知原因?


9
他们真的不同吗?我认为在某些数据库(例如postgresql)中,唯一约束只会创建唯一索引。我没有回答,因为我对sql server一无所知。
xenoterracide

6
在postgresql中,可以在唯一索引中使用表达式,但不能在唯一约束中使用表达式。
尼尔·麦圭根

1
在MS SQL上,它们的实现方式相同。尝试使用相同的数据创建两个表,一个表具有唯一性约束,另一个表具有唯一性索引。它们将使用相同数量的索引空间,并且两者都将能够针对以任何一种方式创建的唯一索引(实际上)。
所有行业的乔恩2015年

Answers:


153

在引擎盖下,唯一约束的实现方式与唯一索引相同-需要一个索引来有效满足强制执行约束的要求。即使索引是由于UNIQUE约束而创建的,如果查询计划程序将索引视为处理给定查询的最佳方法,则它也可以像其他索引一样使用它。

因此,对于同时支持这两种功能的数据库,使用哪种选择通常取决于首选的样式和一致性。

如果您打算将索引用作索引(即您的代码可能很快依赖该字段的搜索/排序/过滤),则可以明确地使用唯一索引(并注释源代码)而不是使用约束来使其clear-这样,如果在应用程序的更高版本中更改了唯一性要求,您(或其他编码人员)将知道确保将非唯一索引替换为唯一索引(仅删除唯一约束将删除完全索引)。还可以在索引提示中命名特定索引(即WITH(INDEX(ix_index_name))),我认为在幕后创建的用于管理唯一性的索引不是这种情况,因为您不太可能知道其名称。

同样,如果您只需要将唯一性作为业务规则来执行,而不是需要搜索或用于排序的字段,那么我将使用约束,以便在其他人查看您的表定义时使用途更加明显。

请注意,如果在同一字段上同时使用唯一约束和唯一索引,则数据库的亮度将不足以查看重复项,因此最终将获得两个索引,这将占用额外的空间并减慢行插入/更新的速度。


1
我想知道“数据库不够明亮”吗?所有的RDBMS都是这样吗?它是由SQL-Standard强制执行的吗?即使是这样(我想知道为什么会这样),所有实现都以这种方式实现吗?或者:为什么数据库不能足够“明亮”?
尔根·艾哈德

4
@jae:一个DBMS当然可以足够明亮,但是您必须与每个DBMS一起检查它是否亮。如果您要求MSSQL创建两个相同的索引,它将创建两个而不是两个被两个名称引用的索引(至少上次我发现这种情况是这种情况(由于我的复制+粘贴错误)),因此,我假设由于约束而存在其中一个索引的情况也是如此。
David Spillett

3
+1 @David Spillett我认为DBMS基本上只是假设您知道自己在做什么;如果您想两次创建相同的索引,就不会对此提出质疑。
Andrew Barber

2
非常有见地。您是否知道这种行为是否也存在于MySQL和Apache Derby中?
corsiKa 2011年

5
可以命名约束并在索引提示中使用它。CREATE TABLE #T(X INT CONSTRAINT PK PRIMARY KEY NONCLUSTERED);SELECT * FROM #T WITH(INDEX(PK)) WHERE X = 1。尽管索引不支持所有索引选项(例如INCLUDEd列或过滤后的索引),但索引可以更灵活。
马丁·史密斯

101

除了其他答案中的要点之外,这还有两者之间的一些关键区别。

注意:错误消息来自SQL Server 2012。

失误

违反唯一约束将返回错误2627。

Msg 2627, Level 14, State 1, Line 1
Violation of UNIQUE KEY constraint 'P1U_pk'. Cannot insert duplicate key in object 'dbo.P1U'. The duplicate key value is (1).
The statement has been terminated.

违反唯一索引将返回错误2601。

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.P1' with unique index 'P1_u'. The duplicate key value is (1).
The statement has been terminated.

禁用

唯一约束不能被禁用。

Msg 11415, Level 16, State 1, Line 1
Object 'P1U_pk' cannot be disabled or enabled. This action applies only to foreign key and check constraints.
Msg 4916, Level 16, State 0, Line 1
Could not enable or disable the constraint. See previous errors.

但是,可以禁用主键约束或唯一约束后面的唯一索引,也可以禁用任何唯一索引。帽子提示Brain2000。

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

请注意通常的警告,即禁用聚簇索引会使数据不可访问。

选件

唯一约束支持诸如FILLFACTOR和的索引选项IGNORE_DUP_KEY,尽管并非每种版本的SQL Server都如此。

包含的栏

非聚集索引可以包括非索引列(称为覆盖索引,这是主要的性能增强)。PRIMARY KEY和UNIQUE约束后面的索引不能包含列。帽子提示@ypercube。

筛选

唯一性约束无法过滤。

可以过滤唯一索引。

CREATE UNIQUE NONCLUSTERED INDEX Students6_DrivesLicence_u 
ON dbo.Students6( DriversLicenceNo ) WHERE DriversLicenceNo is not null ;

外键约束

尽管外键约束可以引用未过滤的唯一索引(我认为这是在SQL Server 2005中添加的),但它不能引用已过滤的唯一索引。

命名

创建约束时,指定约束名称是可选的(对于所有五种约束类型)。如果您未指定名称,则MSSQL将为您生成一个名称。

CREATE TABLE dbo.T1 (
    TID int not null PRIMARY KEY
) ;
GO
CREATE TABLE dbo.T2 (
    TID int not null CONSTRAINT T2_pk PRIMARY KEY
) ;

创建索引时,必须指定名称。

帽子提示@ i-one。

链接

http://technet.microsoft.com/zh-CN/library/aa224827(v=SQL.80).aspx

http://technet.microsoft.com/zh-CN/library/ms177456.aspx


可以通过与索引相同的方法来禁用和启用唯一约束:ALTER INDEX tbl ON uconstraint禁用,ALTER INDEX tbl ON uconstraint重建
Brain2000 '18

谢谢@ Brain2000。巧合的是,今天早晨,在我阅读此评论之前,我教了一个有关禁用索引的部分。
Greenstone Walker

10

引用MSDN作为权威来源:

创建UNIQUE约束和创建独立于约束的唯一索引之间没有显着差异。数据验证以相同的方式发生,并且查询优化器不会区分由约束创建或手动创建的唯一索引。但是,在列上创建UNIQUE约束可以使索引的目标明确... 更多信息,请点击此处

和...

数据库引擎自动创建一个UNIQUE索引,以强制执行UNIQUE约束的唯一性要求。因此,如果尝试插入重复的行,则数据库引擎将返回一条错误消息,指出已违反UNIQUE约束,并且不会将该行添加到表中。除非明确指定一个聚集索引,一个独特的,非聚集索引默认情况下强制执行UNIQUE约束...创建更多资讯

其他到:https : //technet.microsoft.com/zh-cn/library/aa224827%28v=sql.80%29.aspx


6

唯一约束和唯一索引之间的主要区别之一是,另一个表上的外键约束可以引用构成唯一约束的列。对于唯一索引,情况并非如此。另外,唯一约束被定义为ANSI标准的一部分,而索引则未被定义。最后,当索引是物理方面时,唯一约束被认为存在于逻辑数据库设计领域(可能由不同的DB引擎以不同方式实现)。因此,唯一约束更具声明性。在几乎所有情况下,我都希望使用唯一约束。


8
-1在SQL Server中,以下情况是错误的:“另一个表上的外键约束可以引用构成唯一约束的列。对于唯一索引,这不是正确的”。在SQL Server中,我们可以将FK约束引用到唯一索引。
AK 2012年

4
我认为,SQL Server 2005中增加了外键约束引用唯一索引的功能。许多资源(包括BOL中的某些页面)尚未更新以反映更改,因此我认为Dmitry的答案没有该当选。他剩下的答案就在现场-约束是ANSI标准的,索引不是。
Greenstone Walker

尽管这些否决了我最喜欢的答案。
miracle173

标准很重要。如果Ansi标准要使用唯一约束,那么我们应该使用唯一约束。
Rhyous

1

在Oracle中,主要区别在于您可以创建一个函数唯一索引,该索引不能在唯一约束下使用:

例如

create unique index ux_test on my_table (case when amount != 0 then fk_xyz end);

因此fk_xyz只有具有记录才是唯一的amount != 0


7
在SQL Server(问题的标记)中,可以使用WHERE子句过滤索引。CREATE UNIQUE NONCLUSTERED INDEX P4_U ON DBO.P4 ( PID ) WHERE TXT = 'qwert' ;
Greenstone Walker

-3

首选UNIQUE约束优于UNIQUE索引。当约束不是唯一的时,您需要使用常规或非唯一索引。约束也是索引的另一种类型。索引用于更快地访问。

唯一索引可以具有where子句。例如,您可以根据日期列为每年创建索引

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'

很高兴看到提到的where子句好处。
crokusek 2014年

3
“约束也是索引的另一种类型。” 不,不是。一些约束(PK,UQ,FK)可以并且经常通过使用索引来强制执行。不一定,但不是所有DBMS中的默认值。
ypercubeᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.