ror*_*yok 8 sql t-sql sql-server insert exists
我在SQL Server中有一个SP,每分钟运行数百次,需要检查数据库的传入流量.目前它执行以下操作
INSERT INTO table
SELECT @value1,@value2 WHERE NOT EXISTS
(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2);
Run Code Online (Sandbox Code Playgroud)
但是,我也可以去
IF NOT EXISTS(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2)
INSERT INTO table (value1,value2) VALUES (@value1,@value2);
Run Code Online (Sandbox Code Playgroud)
哪个会更快?我觉得它们之间没有太大区别,但我在历史上不太擅长TSQL ...... = /
更新:哎呀...意味着表示EXISTS使用多于1个值来查找是否存在记录,因此唯一约束将不起作用.编辑样本以反映......
两种变体都不正确.您将插入一对重复的@ value1,@ value2,保证.
处理此问题的正确方法是对两列强制执行唯一约束,并始终INSERT并处理约束违规:
ALTER TABLE Table ADD CONSTRAINT uniqueValue1Value UNIQUE (value1, values2);
Run Code Online (Sandbox Code Playgroud)
并插入:
BEGIN TRY
INSERT INTO Table (value1, value2) VALUES (@value1, @value2);
END TRY
BEGIN CATCH
DECLARE @error_number int, @error_message NVARCHAR(4000), @xact_state INT;
SET @error_number = ERROR_NUMBER();
SET @error_message = ERROR_MESSAGE();
SET @xact_state = XACT_STATE();
IF (@xact_state = -1)
BEGIN
ROLLBACK TRANSACTION;
END
IF (@error_number != 2627) /* 2627 is ' Cannot insert duplicate key in object ...' */
BEGIN
RAISERROR(N'Error inserting into Table: %i %s', 16,1, @errror_number, @error_message);
END
ENd CATCH
Run Code Online (Sandbox Code Playgroud)
虽然这些看似复杂,但必须考虑一些名为正确性的细节.与基于锁定提示的解决方案相比,这简单得多.这也是最高效的解决方案:只有一个寻求.所有其他解决方案至少需要两次搜索(一次验证可以插入,一次插入).
在对这个问题及其答案添加了无数评论之后,我将继续回答它。
我预计原始问题中提出的两个提议之间不会有任何重大的性能差异。一方面,正如 Ray 所指出的,第二种方法可能会让您免于为插入做一些准备工作,但另一方面,RDBMS 通常在使用批处理语句时性能最佳,如第一种解决方案。
KM 和 DVK 建议添加一个UNIQUE约束,这将使唯一性测试变得隐式,但需要您在语句周围添加某种错误处理INSERT。假设您已经有一个覆盖两列的索引,我很难找出为什么这会增加任何额外的性能。如果您没有此类索引,请添加它,并重新考虑您对更高性能的需求。
AFAIK 是否显式或隐式执行唯一性检查并不重要。如果通过在 DBMS“内部”完成检查获得任何好处,那么该收益可能会被与存在重复项时引发和处理错误相关的开销所吞噬。
底线:假设索引已经到位,如果您仍然发现自己渴望性能,我的建议是您对三个建议的解决方案进行实证测试。编写一个小程序来模拟预期的输入数据,并用数十亿行(包括合理数量的重复项)消除这三个解决方案中的每一个。执行此操作,请务必发布您的结果:-)