Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which is faster, EXISTS before or after the INSERT?

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...

like image 788
roryok Avatar asked Feb 17 '10 16:02

roryok


1 Answers

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).

like image 98
Remus Rusanu Avatar answered Sep 28 '22 07:09

Remus Rusanu