【问题标题】:How do I create a multiple column unique constraint in SQL Server如何在 SQL Server 中创建多列唯一约束
【发布时间】:2012-07-30 02:00:53
【问题描述】:

我有一个表,其中包含例如我想在数据库中设置唯一的两个字段。例如:

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 万行)。

有没有更有效的方法来实现这种类型的约束?

【问题讨论】:

  • 你是说没有索引的搜索比有索引的搜索要快得多吗?这对我来说是个新闻,据我所知,创建索引总是为了加快搜索速度,而不是减慢搜索速度。
  • 不,仅此而已,但它应该不会对您的搜索时间产生任何重大影响?!我们谈论的影响有多大?你能展示一下执行计划吗?您是否更新了统计信息?
  • 在 Email 和 DataSetId 上使用“简单”索引搜索电子邮件地址大约需要 1 秒。通过添加额外的复合索引,这增加到大约 9 秒。
  • 我整个早上都在玩这个,实际上我认为我有一个不同的问题......我看到的性能下降是从 UI(我知道,我知道)一个 MVC 网络测量的使用 LINQ 的页面。添加索引时,它确实显示出显着的性能下降。如果我从 LINQ 中获取 SQL 表达式并直接在 SQL Server Management Studio 中运行它,那么我实际上会看到性能提升(使用索引)。所以,很抱歉误导了大家。但我不明白的是,为什么 LINQ 表达式在从网页运行时,实际上运行速度要慢 10 倍。

标签: sql-server indexing duplicates


【解决方案1】:

但我发现这对搜索时间有相当大的影响 (例如在搜索电子邮件地址时

您在(DataSetId, Email) 上定义的索引不能用于基于电子邮件的搜索。如果您要在最左边的位置创建一个带有Email 字段的索引,则可以使用它:

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

此索引将作为唯一约束强制执行作为快速搜索电子邮件的一种手段。这个索引虽然不能用于快速搜索特定的DataSetId

它的要点是,无论何时定义多键索引,它都只能用于按键的顺序进行搜索。 (A, B, C) 上的索引可用于查找列 A 上的值,用于搜索 两个 AB 上的值或搜索所有三个列上的值 A, @ 987654332@ 和C。但是,它不能用于单独搜索 BC 上的值。

【讨论】:

  • 全部正确,但这并不能解释添加索引如何对搜索时间产生负面影响(显着)
  • @Lieven:我怀疑 OP 不仅仅是创建一个新的约束。例如。它删除了Email上的现有索引
  • 很可能但转述Elmer Fud,OP vewy vewy quiet
  • 现在你只是在传播Fud ;)
  • 好的,我认为您突出显示了一个我不完全理解的区域,也许您可​​以提供帮助... 目前 DataSetID 列和 Email 列都已编入索引,因为我需要查找/过滤记录在 DataSetId 或/或电子邮件地址上。根据您所说,我可以删除电子邮件索引并替换为 ON 订阅者(电子邮件,DataSetId),但是如果我“只是”想按 DataSetId 过滤,我不会遇到同样的性能问题吗?
【解决方案2】:

我假设将数据输入该表的唯一方法是通过 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

【讨论】:

  • -1 用于推荐程序解决方案而不是强制执行。此外,该过程不会在并发下工作。
  • @RemusRusanu procedure would not work under concurrency 这是什么意思?
  • 多个事务可以同时检查条件,得出没有重复的结论。所有线程继续插入,创建重复项。 check and insert 编码模式是一个众所周知的问题:sqlblog.com/blogs/alexander_kuznetsov/archive/2010/01/12/…
猜你喜欢
  • 2010-09-09
  • 2010-12-22
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 2012-01-04
  • 1970-01-01
相关资源
最近更新 更多