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语句发生).
我看过那篇文章,但请注意,对于低失败率,我更喜欢“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)