【问题标题】:How to handle in an effective way duplicate key insertions w/out throwing an exception如何以有效的方式处理重复键插入而不会引发异常
【发布时间】:2011-09-12 09:54:34
【问题描述】:

我的案例场景将参数传递给一个过程,该过程只进行插入。但是两个线程可能会尝试传递相同的值。

如何在不抛出异常和使用最少锁的情况下处理这种情况?

我的性能要求是每秒至少 10k 次插入。

编辑: 列是唯一的。时间戳可能会在插入之前更改(调整)。

【问题讨论】:

  • 该表是否有任何唯一约束?
  • 您希望他们失败或纠正重复的密钥?
  • @Matten 我宁愿更正重复的键(可能增加)。失败是什么意思?
  • @heximal 我的场景是重复键问题 - 所以它是一个唯一的列。
  • 见链接in this answer

标签: sql-server tsql nonblocking sqlperformance transaction-isolation


【解决方案1】:

使用忽略重复键选项在表上创建索引。它不会插入重复的行,也不会出现任何错误。

例如

create unique index i1 on #tmp(id) with ignore_dup_key

insert into #tmp values(1,"A")
2> go
(1 row affected)


1> insert into #tmp values(1,"A")
2> go
Duplicate key was ignored.
(0 rows affected)

【讨论】:

    【解决方案2】:

    试试MERGE 语句

    来自 MSDN 。一种常见的情况是,如果存在匹配行,则更新表中的一个或多个列,或者如果匹配行不存在,则将数据作为新行插入。这通常通过将参数传递给包含适当 UPDATE 和 INSERT 语句的存储过程来完成。使用 MERGE 语句,您可以在一条语句中执行这两项任务。

    关于你的性能问题,Optimizing MERGE Statement Performance上也有一个页面

    【讨论】:

    • 如果有两个相同的值,我希望其中一个被更改(或其他,但不被覆盖)- Merge 语句会这样做吗?
    • @Falcon:是的,一旦您发现记录是否存在,您几乎可以做任意事情。
    【解决方案3】:

    正如 @Martin Smith 指出的那样,有一个很好的解决方案——即使它与我的问题相反,但它背后有很好的理由,似乎得到了很好的支持。您可以找到 @gbn 发布的here 的原始答案。

    BEGIN TRY
       INSERT etc
    END TRY
    BEGIN CATCH
        IF ERROR_NUMBER() <> 2627
          RAISERROR etc
    END CATCH
    

    说真的,这是最快的,并且在没有锁的情况下并发最多,尤其是在大容量时。如果UPDLOCK升级,整个表被锁定怎么办?

    Paul Nielsen 的原文你可以找到here。 - 第 4 课。

    如果有人和我有类似的问题,可以看看。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-06
      • 1970-01-01
      • 1970-01-01
      • 2013-01-26
      • 2014-09-15
      • 2014-12-16
      • 2015-12-12
      相关资源
      最近更新 更多