2012-08-01 166 views
13

我有一個表,其中包含例如兩個字段,我想在數據庫中使其唯一。例如:如何在SQL Server中創建多列唯一約束

create table Subscriber (
    ID int not null, 
    DataSetId int not null, 
    Email nvarchar(100) not null, 
    ... 
) 

ID列是主鍵,DataSetId和Email都被編入索引。

我想要做的就是防止表中出現相同的Email和DataSetId組合,或者換句話說,對於給定的DataSetId,Email值必須是唯一的。

我試圖在列

CREATE UNIQUE NONCLUSTERED INDEX IX_Subscriber_Email 
ON Subscriber (DataSetId, Email) 

創建唯一索引,但我發現,這對搜索時間相當顯著影響(電子郵件地址,例如搜索時 - 有在150萬行表)。

是否有更高效的方式來實現這種類型的約束?

+0

你是說沒有索引的搜索比使用索引快得多?這對我來說是新聞,據我所知,索引總是爲了加快搜索速度而創建的,而不是放慢搜索速度。 – 2012-08-01 07:51:25

+0

不,這就是它,但它不應該對搜索時間有任何**顯着影響?!我們談論的影響有多大?你能展示執行計劃嗎?你有更新統計數據嗎? – 2012-08-01 07:52:03

+0

在Email和DataSetId上使用'簡單'索引搜索電子郵件地址花費了大約1秒。通過添加額外的化合物指數,這增加到約9秒。 – Neilski 2012-08-01 12:24:32

回答

25

,但我發現這個搜索電子郵件地址,例如

您定義的索引時對搜索時間 (相當顯著的影響(DataSetId, Email)不能用於基於電子郵件的搜索。如果要在最左邊的位置使用Email字段創建索引,則可以使用它:

CREATE UNIQUE NONCLUSTERED INDEX IX_Subscriber_Email 
    ON Subscriber (Email, DataSetId); 

該索引將作爲唯一約束強制執行作爲快速搜索電子郵件的手段。儘管此索引不能用於快速搜索特定DataSetId

它的要點是,只要你定義一個多鍵索引,它只能用於按鍵的順序進行搜索。在(A, B, C)索引可以被用來尋求A列值,對所有三列ABC搜索值都AB或搜索值。但是,它不能用於單獨搜索BC上的值。

+0

所有這一切都是真實的,但這並不能解釋如何添加索引負面影響搜索時間*(顯着)* – 2012-08-01 08:03:13

+0

@Lieven:我懷疑OP不僅僅是創建一個新約束。例如。它放棄了現有的電子郵件索引 – 2012-08-01 08:08:34

+1

很可能,但是用[Elmer Fud](http://en.wikipedia.org/wiki/Elmer_Fudd)來解釋,OP是* vewy vewy quiet * 2012-08-01 08:15:47

-1

我假設只有通過SP才能將數據輸入到表中,如果是這種情況,您可以在插入和執行SP時查找是否已經存在將要插入/更新的值該表是否。

像這樣的事情

create proc spInsert 
(
    @DataSetId int, 
    @Email nvarchar(100) 
) 
as 
begin 

if exists (select * from tabaleName where DataSetId = @DataSetId and Email = @Email) 
    select -1 -- Duplicacy flag 
else 
begin 
    -- insert logic here 
    select 1 -- success flag 
end 

end 
GO 


create proc spUpdate 
(
    @ID int, 
    @DataSetId int, 
    @Email nvarchar(100) 
) 
as 
begin 

if exists 
(select * from tabaleName where DataSetId = @DataSetId and Email = @Email and ID <> @ID) 
    select -1 -- Duplicacy flag 
else 
begin 
    -- insert logic here 
    select 1 -- success flag 
end 

end 
GO 
+0

-1用於推薦程序性解決方案而不是強制執行。此外,該過程在併發下不起作用。 – 2012-08-01 08:01:16

+0

@RemusRusanu'過程不會在併發下工作'你是什麼意思? – yogi 2012-08-01 08:04:08

+1

多個事務可以檢查條件*併發*並斷定沒有重複。所有線程繼續插入,創建重複項。使用'check and insert'編碼模式是一個衆所周知的問題:http://sqlblog.com/blogs/alexander_kuznetsov/archive/2010/01/12/t-sql-tuesday-002-patterns-that-do-not -work-as-expected.aspx – 2012-08-01 08:11:52