我有一个名为的表,我通过在 SQL Server 2008 R2 上创建类型为“唯一键”的“索引/键”来countries
定义该列是唯一的。country_name
但我有以下问题:
- 创建“唯一键”类型的“索引/键”会自动在该列上创建非聚集索引吗?
- 如果我将类型从“唯一键”更改为“索引”,并将
IsUnique
值保持为“是”,那么会有什么不同吗? - 那么为什么有两个选项“唯一键”和“索引”我认为两者是一样的?
我有一个名为的表,我通过在 SQL Server 2008 R2 上创建类型为“唯一键”的“索引/键”来countries
定义该列是唯一的。country_name
但我有以下问题:
IsUnique
值保持为“是”,那么会有什么不同吗?唯一约束在幕后实现为唯一索引,因此如何指定它并不重要。我倾向于简单地实现它:
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
) 来解决此问题。
另外要提到的一件事是,如果您创建索引,则可以指定包含的列,如果按国家/地区名称进行搜索,这可以帮助您的 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 服务器会将“foo_other_column”存储在索引本身中。在唯一约束的情况下,它将首先找到“test”的索引,然后在 foo 表中搜索行,只有在那里才会采用“foo_other_column”。
除了上面的出色答案外,我还要在这里加 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;
我们将得到以下内容(约束和索引)
但是,如果我们不创建约束而只创建唯一索引,如下所示
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
您将看到没有创建约束对象(仅创建了一个索引)。
从“理论上”的角度来看,在 SQL Server 中,约束是具有 object_id 值的对象并且是模式绑定的,而索引不是对象并且没有 object_id 值并且与模式无关。
唯一索引或唯一约束之间没有区别,也没有性能差异。但是,创建时存在一些差异,其中某些索引创建选项不适用于唯一约束。
如果您使用 SqlMetal.exe 输出 DBML 或 LinqToSql 实体:
原因在于SqlMetal 的实现。它查询数据库信息架构,特别是关键列的使用情况。那里表示唯一键,但没有唯一索引。
SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME, ORDINAL_POSITION
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE;
最重要的一点是假设您希望通过保持唯一性来保持列值为空,而唯一键约束无法做到这一点,但是使用唯一键索引,您可以在保持唯一性的情况下保持列值空。因此,如果您需要具有可空类型的唯一列,则需要唯一索引,否则如果您需要不可为空的列,则需要唯一键约束。
强制唯一性的第三个选项是使用过滤的唯一索引来允许为空的唯一索引。
这不适用于唯一约束。
例如,假设您有一列只想允许唯一值,但在多个值不存在时
仍希望支持它们。
只有过滤的唯一索引才能工作: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 而不是手动创建索引(如上),您可以关闭所有打开的表设计器,然后在对象资源管理器中打开索引本身的属性。