簡體   English   中英

SQL Server 2008上的唯一鍵與唯一索引

[英]Unique key vs. unique index on SQL Server 2008

我有一個名為countries的表,我通過在SQL Server 2008 R2上創建“唯一鍵”類型的“索引/鍵”來將country_name列定義為唯一。

但我有以下問題:

  1. 將創建“唯一鍵”類型的“索引/鍵”自動在此列上創建非聚集索引?
  2. 如果我將類型從“唯一鍵”更改為“索引”並且我將IsUnique值保持為“是”,那么會有任何差異嗎?
  3. 那么為什么有兩個選項“Unique Key”和“Index”我認為兩者是一樣的?

在幕后將唯一約束作為唯一索引實現,因此指定它並不重要。 我傾向於簡單地實現它:

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 )來解決此問題。

還有一點需要注意的是,如果您創建索引,則可以指定包含的列,如果通過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服務器將在索引本身中存儲“foo_other_column”。 在唯一約束的情況下,它將首先找到'test'的索引,然后將在foo表中搜索行,並且僅在那里它將采用“foo_other_column”。

唯一索引或唯一約束之間沒有區別,也沒有性能差異。 但是,創建時存在一些差異,其中某些索引創建選項不可用於唯一約束。

如果您使用SqlMetal.exe輸出DBML或LinqToSql實體:

  • 如果外鍵使用唯一鍵,那么您將獲得預期的關聯。
  • 如果外鍵使用唯一索引,則不會顯示。

原因是在實現SqlMetal。 它查詢數據庫信息模式,特別是關鍵列使用情況。 在那里表示唯一鍵,但不是唯一索引。

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

除了上面的優秀答案,我在這里加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值且沒有與模式相關。

強制唯一性的第三個選項是使用Filtered Unique-Index來允許Nullable Unique Index。
不適用於Unique-Constraints。
例如,假設您有一個列,您只想允許唯一值,
但是當它們不存在時仍然希望支持多個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中創建Filtered-Index。
但是,如果您想通過GUI而不是手動創建索引(如上所述),則可以關閉所有打開的表設計器,然后在對象資源管理器中打開索引本身的屬性。

最重要的一點是假設您希望保持列值null並保持唯一性,而不能使用唯一鍵約束但使用唯一鍵索引u可以使列值保持為null並保持唯一性。 因此,如果您需要具有Null-able類型唯一索引的列唯一索引,如果您需要列不能為空,則需要唯一鍵約束。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM