【问题标题】:Unique key vs. unique index on SQL Server 2008SQL Server 2008 上的唯一键与唯一索引
【发布时间】:2012-05-03 01:46:24
【问题描述】:

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

但我有以下问题:

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

【问题讨论】:

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


【解决方案1】:

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

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

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

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

区别在于意图 - 如果您创建约束以强制执行唯一性/业务规则,则创建约束,如果您这样做是为了提高查询性能,则创建唯一索引可能更合乎逻辑。同样,在幕后它是相同的实现,但您实现目标的路径可能有助于记录您的意图。

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

【讨论】:

  • 不确定是否只是信息区分,但sys.indexesis_unique_constraint 列来判断索引是否被定义为约束而不是唯一索引。
  • @Andre 是的,这是元数据中的一列,以便 用户 可以判断它是否最初被声明为约束。这并没有告诉您任何有关意图的信息,并且索引本身的物理实现 - 以及唯一性执行 - 是相同的。
【解决方案2】:

另外要提一提的是,如果您创建索引,则可以指定包含列,如果有一些按国家/地区名称搜索的情况,这可以帮助您的 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”。

【讨论】:

    【解决方案3】:

    除了上面的优秀答案之外,我会在这里加上我的 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 值并且与模式无关。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

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

        【讨论】:

        • 这与历史观念一致,即唯一键是数据模型的基本部分(参照完整性),而索引只是实现细节(查询性能优化)。
        【解决方案6】:

        强制唯一性的第三个选项是使用过滤的唯一索引来允许可空唯一索引。
        适用于 Unique-Constraints。
        例如,假设您有一列只想允许唯一值,
        但仍希望支持多个不存在的 NULL 值。
        只有 Filtered Unique-Index 可以工作:

        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 而不是手动创建索引(如上),您可以关闭所有打开的表设计器,然后在对象资源管理器中打开索引本身的属性。

        【讨论】:

          【解决方案7】:

          最重要的一点是假设您希望保持列值为空并保持唯一性,但您无法使用唯一键约束但使用唯一键索引您可以保持列值为空并保持唯一性。 因此,如果您需要具有可空类型的唯一列,则需要唯一索引,否则如果您需要不可为空的列,则需要唯一键约束。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-11-28
            • 2013-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-26
            • 1970-01-01
            • 2011-03-11
            • 1970-01-01
            相关资源
            最近更新 更多