I have an SP in SQL Server which runs hundreds of times a minute, and needs to check incoming traffic against a database. At the moment it does the following
INSERT INTO table
SELECT @value1,@value2 WHERE NOT EXISTS
(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2);
However, I could also go with
IF NOT EXISTS(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2)
INSERT INTO table (value1,value2) VALUES (@value1,@value2);
Which would be faster? I get the feeling there's not much difference between them but I'm historically not very good at TSQL... =/
UPDATE: Whoops... meant to state that the EXISTS uses more than 1 value to find if a record exists, so a unique constraint won't work. Edited the sample to reflect that...
Both variants are incorrect. You will insert pairs of duplicate @value1, @value2, guaranteed.
The correct way to handle this is to enforce a unique constraint on two columns and to always INSERT and handle the constraint violation:
ALTER TABLE Table ADD CONSTRAINT uniqueValue1Value UNIQUE (value1, values2);
and to insert:
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
While these may seem complicated, one has to factor in a little detail named correctness. This is by far simpler when compared with a lock hints based solution. This is also the most performant solution: does only one seek. All other solutions need at least two seeks (one to validate that it can be inserted, one to insert).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With