约束检查:try / catch语句VS是否存在()(Constraints check: TRY/

2019-06-25 10:57发布

我有它独特的约束的表:

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

其代码是更好地重复检查(成功= 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

选项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

从我的视图-我相信这一点Try/Catch是错误的,并没有预期(如僵局甚至限制不希望重复时)。 在这种病例很可能有时用户会尝试提交重复,所以预计该错误。

我发现亚伦伯特兰文章认为明─检查重复并不慢得多,即使大多数刀片是成功的。

也有过网建议的负载使用的try / catch(避免2条语句不是1)。 在我的环境有可能是一样的未果的情况下1%,所以那种有道理了。

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

更新:我不知道这是在这种情况下很重要,但表具有替代更新触发器(用于审计目的订立行删除也正好通过Update语句)。

Answer 1:

我已经看到了文章,但请注意,低故障率我会更喜欢“JFDI”的格局。 我用这个之前高容量系统(40K行/秒)。

在阿龙的代码,你可以在高负载和大量写入下先进行测试时,仍然得到重复。 (这里解释dba.se )这一点很重要:你重复的还是发生了,只是不经常。 您还需要异常处理,并知道何时忽略重复的错误(2627)

编辑:在另一个答案简洁解释由瑞摩斯

不过,我想有一个单独的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


Answer 2:

首先,在EXISTS(SELECT ...)是不正确的,它失败下并发:多个事务可以同时运行检查,所有的结论是他们必须插入,一个将成为幸运的获奖者是首先插入,其余全部将打击违反约束。 换句话说,你必须检查和刀片之间的竞争条件。 所以,你必须的try / catch 无论如何 ,所以更好的刚try / catch语句。



Answer 3:

错误记录

请不要把我这一点,但有些时候抛出一个异常可能记录的影响。 如果您在插入前检查没有这样的事情发生。

知道为什么,当它可以打破

try / catch块应该用于能够打破非确定性的原因部分。 我会说这是你的情况比较明智的检查现有的记录,因为你知道它可以打破和到底为什么。 因此,检查它自己是从开发人员的角度来看一个更好的办法。

但是,在你的代码仍可能在插入时中断,因为之间的检查时间,并插入一些其他时间用户插入它已经......但事实(如前面说的)不确定性的错误。 这就是为什么你:

  1. 应与被检查exists
  2. 中插入try/catch

言自明代码

另一个积极的也是很普通的从代码为什么会破裂而try / catch块可以隐藏和一个可以删除它们想明白为什么会在这里,它只是插入记录 ...



Answer 4:

选项 - 3

Begin Try
    SET XACT_ABORT ON
    Begin Tran
        IF NOT EXISTS (Select 1 From MyTab Where SomeValue = @someValue)
        Begin
            Insert Into MyTab(SomeValue) Values ('aaa');
        End
    Commit Tran
End Try

begin Catch
    Rollback Tran
End Catch


Answer 5:

为什么不实行INSTEAD OF INSERT在桌子上触发? 您可以检查是否此行存在,什么都不做,如果是的话,然后插入该行,如果它没有。



文章来源: Constraints check: TRY/CATCH vs Exists()