|
|
|
SSC-Addicted
      
Group: General Forum Members
Last Login: Wednesday, May 15, 2013 5:02 AM
Points: 403,
Visits: 904
|
|
Hi,
SQL Server has the MERGE statement and some people advise to use it instead of IF EXISTS with INSERT / UPDATE... Is it worth upgrading from IF EXISTS .. to MERGE?
CREATE PROCEDURE usp_Upsert_teste1_1 @ID INT, @Desc VARCHAR(100) AS IF EXISTS (SELECT TOP 1 1 FROM teste1 WHERE ID = @ID) UPDATE teste1 SET Description = @Desc WHERE ID = @ID ELSE INSERT INTO teste1 (ID, Description) VALUES (@ID, @Desc) GO CREATE PROCEDURE usp_Upsert_teste1_2 @ID INT, @Desc VARCHAR(100) AS MERGE teste1 AS target USING (SELECT @ID, @Desc) AS source (ID, Dsc) ON target.ID = source.ID WHEN MATCHED THEN UPDATE SET target.Description = source.Dsc WHEN NOT MATCHED THEN INSERT (ID, Description) VALUES (source.ID, source.Dsc);
The execution plan is slower on the 1st sp because of the IF... The INSERT or UPDATE are as fast (according to execution plan) as the MERGE.
Thanks, Pedro
If you need to work better, try working less...
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:55 PM
Points: 15,442,
Visits: 9,571
|
|
If you need to maintain backwards compatibility with versions of SQL Server prior to 2008, then don't use Merge. Otherwise, it does have advantages.
The main advantage, from my perspective, is that you can do the action in one statement. That means less code to maintain, and it's obvious that it's an upsert instead of possibly two different actions. And, since a Merge statement can use either an Output Into or be wrapped in an Insert Select with a simpler Output clause, you can do your logging in one place instead of two (if you need to do audit logging, that is).
It also has advantages over Update From, if you use that, because it will throw an error instead of doing the wrong thing, if two rows could end up updating the same row in the destination.
If 99% of the time, an Update will happen, then you're better off with:
Update if @@rowcount = 0 Insert
More efficient that way.
Beyond those points, it's really up to you. I like Merge, but it took a while to get used to the syntax.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|
|
SSCrazy
      
Group: General Forum Members
Last Login: Yesterday @ 10:39 AM
Points: 2,556,
Visits: 4,398
|
|
And another thing to mention for MERGE is that SQL Server kind of splits the data into up to three "streams" and executes INSERT, UPDATE and DELETE (if required). So, for example, if you have a single trigger for INSERT, UPDATE, DELETE it will still be executed separately three times. You have no control over what will happen first, as order of execution is not guaranteed... Another small caveat for using INSTEAD OF triggers, in case if you want use MERGE, they should not be present at all or they should be implemented for all three operations.
_____________________________________________ "The only true wisdom is in knowing you know nothing" "O skol'ko nam otkrytiy chudnyh prevnosit microsofta duh!" (So many miracle inventions provided by MS to us...)
How to post your question to get the best and quick help
|
|
|
|
|
SSCarpal Tunnel
       
Group: General Forum Members
Last Login: Yesterday @ 9:39 AM
Points: 4,247,
Visits: 9,500
|
|
One thing which I have noticed with MERGE is that it does not natively provide separate Updated/Inserted/Deleted counts.
You need to code an OUTPUT clause and use $Action to get these. Without that you just get a total 'rows affected' count in @@RowCount.
____________________________________________________________________________________________
Help us to help you. For better, quicker and more focused answers to your questions, consider following the advice in this link:
http://www.sqlservercentral.com/articles/Best+Practices/61537/
If you are asking for help and your post does not contain a question, you should expect responses which do not contain any answers. Put a question mark in there somewhere - it's not rocket science.
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:55 PM
Points: 15,442,
Visits: 9,571
|
|
Phil Parkin (9/19/2012) One thing which I have noticed with MERGE is that it does not natively provide separate Updated/Inserted/Deleted counts.
You need to code an OUTPUT clause and use $Action to get these. Without that you just get a total 'rows affected' count in @@RowCount.
Yep. And that can be a good thing if you want the count for an atomic upsert, or a bad thing if you need to know which had which counts. Still, can be done within the statement, instead of 3 counts (one for each action). And, if you use Pivot on the Output, you can even get all three counts in a single row, which is kind of cool.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|
|
SSCrazy
      
Group: General Forum Members
Last Login: Yesterday @ 7:24 PM
Points: 2,346,
Visits: 3,192
|
|
GSquared (9/19/2012)
Phil Parkin (9/19/2012) One thing which I have noticed with MERGE is that it does not natively provide separate Updated/Inserted/Deleted counts.
You need to code an OUTPUT clause and use $Action to get these. Without that you just get a total 'rows affected' count in @@RowCount.Yep. And that can be a good thing if you want the count for an atomic upsert, or a bad thing if you need to know which had which counts. Still, can be done within the statement, instead of 3 counts (one for each action). And, if you use Pivot on the Output, you can even get all three counts in a single row, which is kind of cool.
Unless I'm mistaken, it would be even cooler if you could assign the 3 PIVOTed columns directly to local variables instead of being forced to INSERT them into a 3 column table in the outer wrapper of the composable DML.
No loops! No CURSORs! No RBAR! Hoo-uh!
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
Need to UNPIVOT? Why not CROSS APPLY VALUES instead? Since random numbers are too important to be left to chance, let's generate some! Are you too recursively challenged? Splitting strings based on patterns can be fast!
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:55 PM
Points: 15,442,
Visits: 9,571
|
|
dwain.c (9/20/2012)
GSquared (9/19/2012)
Phil Parkin (9/19/2012) One thing which I have noticed with MERGE is that it does not natively provide separate Updated/Inserted/Deleted counts.
You need to code an OUTPUT clause and use $Action to get these. Without that you just get a total 'rows affected' count in @@RowCount.Yep. And that can be a good thing if you want the count for an atomic upsert, or a bad thing if you need to know which had which counts. Still, can be done within the statement, instead of 3 counts (one for each action). And, if you use Pivot on the Output, you can even get all three counts in a single row, which is kind of cool. Unless I'm mistaken, it would be even cooler if you could assign the 3 PIVOTed columns directly to local variables instead of being forced to INSERT them into a 3 column table in the outer wrapper of the composable DML.
Yeah, would be very cool if Output worked more like Select, and could assign values to variables using inline sub-queries and things like that. Maybe a future version will.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|
|
Hall of Fame
       
Group: General Forum Members
Last Login: Today @ 2:30 PM
Points: 3,582,
Visits: 5,131
|
|
For concurrency reasons it is MUCH preferred to use MERGE I think. I have seen a number of clients over the years get bad data in their system doing multiple steps for what you are trying to do.
Do be careful if you have triggers on your tables though, or if you need to test @@ROWCOUNT. Some unexpected things can arise.
Best,
Kevin G. Boles SQL Server Consultant SQL MVP 2007-2012 TheSQLGuru at GMail
|
|
|
|
|
SSCoach
         
Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:55 PM
Points: 15,442,
Visits: 9,571
|
|
TheSQLGuru (9/21/2012) For concurrency reasons it is MUCH preferred to use MERGE I think. I have seen a number of clients over the years get bad data in their system doing multiple steps for what you are trying to do.
Do be careful if you have triggers on your tables though, or if you need to test @@ROWCOUNT. Some unexpected things can arise.
Yeah, if you do the multi-step version, transaction control is critical. That's for sure!
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
|
|
|
|
|
SSCommitted
      
Group: General Forum Members
Last Login: Tuesday, January 15, 2013 11:11 AM
Points: 1,945,
Visits: 2,782
|
|
MERGE gets rid of procedural code and it is ANSI/ISO Standard. Use it. In the future, MS will steal optimizations that IBM and Oracle have had for years and incorporate them. MERGE can only get better.
Books in Celko Series for Morgan-Kaufmann Publishing Analytics and OLAP in SQL Data and Databases: Concepts in Practice Data, Measurements and Standards in SQL SQL for Smarties SQL Programming Style SQL Puzzles and Answers Thinking in Sets Trees and Hierarchies in SQL
|
|
|
|