问题
I have a merge statement like below
MERGE DESTINATION AS DST
USING ( SELECT <Some_Columns> FROM TABLEA WITH(NOLOCK) INNER JOIN TableB .....
) AS SRC
ON(
<some conditions>
)
WHEN MATCHED THEN
UPDATE SET column1 = src.column1
...............
,Modified_By = @PackageName
,Modified_Date = GETDATE()
WHEN NOT MATCHED THEN
INSERT (<Some_Columns>)
VALUES(<Some_Columns>)
OUTPUT
$action, inserted.key'inserted'
INTO @tableVar
;
For the first set of records (around 300,000) it is working perfectly and executing in just 30 seconds. But for the second set of records (around 300,000) it is taking more than an hour.
Two days back I have loaded 50 sets like that and the same query was working lightning fast, but from today it is damn slow. I have no idea what is going wrong.
Note: Query
SELECT FROM TABLEA WITH(NOLOCK) INNER JOIN TableB .....
is taking 20 seconds in all scenerios.
回答1:
While the MERGE
syntax is nicer, and it seems to promise better atomicity and no race conditions (but doesn't, unless you add HOLDLOCK, as this Dan Guzman post demonstrates), I still feel like it is better to hang onto the old-style, separate insert/update methodology. The primary reason is not that the syntax is hard to learn (which it is), or that it is difficult to work around the concurrency issues (it isn't), but rather that there are several unresolved bugs - even in SQL Server 2012 still - involving this operation. I point a dozen of them out in this post that talks about yet another MERGE bug that has been fixed recently. I also go into more detail in a cautionary tip posted here.
As I suggested in a comment, I don't want to sound the alarms that the sky is falling, but I'm really not all that interested in switching to MERGE
until there are far fewer active bugs. So I would recommend sticking with an old-fashioned UPSERT
for now, even though the actual syntax you're using might not be the source of the performance problem you're having anyway.
UPDATE dest SET column1 = src.column1
FROM dbo.DestinationTable AS dest
INNER JOIN (some join) AS src
ON (some condition);
INSERT dest(...) SELECT cols
FROM (some join) AS src
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.DestinationTable
WHERE key = src.key
);
For the performance issue, you'll want to look into your session's waits (SQL Sentry's Plan Explorer PRO* can help with that, by firing up an Extended Events session for you), or at the very least, blocking_session_id
and wait_type_desc
in sys.dm_exec_requests
while the query is running.
*Disclaimer: I work for SQL Sentry.
来源:https://stackoverflow.com/questions/15341831/performance-issue-in-merge-statement