2012-08-01 161 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