约束检查:TRY/CATCH vs Exists()

Jān*_*nis 7 sql-server sql-server-2005 sql-server-2008

我有一个具有独特约束的表:

create table dbo.MyTab
(
    MyTabID int primary key identity,
    SomeValue nvarchar(50)
);
Create Unique Index IX_UQ_SomeValue 
On dbo.MyTab(SomeValue);
Go
Run Code Online (Sandbox Code Playgroud)

哪个代码更适合检查重复项(如果找到重复项,则成功= 0)?

选项1

Declare @someValue nvarchar(50) = 'aaa'
Declare @success bit = 1;
Begin Try 
    Insert Into MyTab(SomeValue) Values ('aaa');
End Try
Begin Catch
    -- lets assume that only constraint errors can happen
    Set @success = 0;
End Catch
Select @success
Run Code Online (Sandbox Code Playgroud)

选项2

Declare @someValue nvarchar(50) = 'aaa'
Declare @success bit = 1;
IF EXISTS (Select 1 From MyTab Where SomeValue = @someValue)
    Set @success = 0;
Else 
    Insert Into MyTab(SomeValue) Values ('aaa');
Select @success
Run Code Online (Sandbox Code Playgroud)

从我的角度来看 - 我确实认为这Try/Catch是错误的,不是预期的(如死锁,甚至是不期望重复的约束).在这种情况下,有时用户可能会尝试提交重复,因此错误是预期的.

我发现Aaron Bertrand撰写的文章指出,即使大多数插入成功,检查重复项也不会太慢.

网上还有很多建议可以使用Try/Catch(避免2个语句不是1).在我的环境中,可能只有1%的不成功案例,所以这种情况也是有道理的.

你有什么意见?使用选项1或选项2的其他原因是什么?

更新:我不确定它在这种情况下是否重要,但是表有而不是更新触发器(出于审计目的 - 行删除也通过Update语句发生).

gbn*_*gbn 5

我看过那篇文章,但请注意,对于低失败率,我更喜欢“JFDI”模式。我以前在大容量系统上使用过它(40k 行/秒)。

在 Aaron 的代码中,在高负载和大量写入下进行第一次测试时,您仍然可以得到重复。(在dba.se解释)这很重要:您的重复仍然会发生,只是不那么频繁。您仍然需要异常处理并知道何时忽略重复错误 (2627)

编辑:Remus 在另一个答案中简洁地解释了

不过,我想有一个单独的try / catch测试针对重复错误

BEGIN TRY

-- stuff

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

--more stuff

BEGIN CATCH
    RAISERROR etc
END CATCH
Run Code Online (Sandbox Code Playgroud)