我有一个像下面这样的合并语句
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
;
对于第一组记录(大约300,000),它工作得很好,并且在30秒内执行。但第二项记录(约30万人)却花了一个多小时。
两天前我加载了50个这样的集合,同样的查询工作速度很快,但从今天开始它就慢了。我不知道哪里出错了。
注意:查询
SELECT FROM TABLEA WITH(NOLOCK) INNER JOIN TableB .....
在所有情况下都需要20秒
虽然MERGE
语法更好,而且似乎承诺更好的原子性和没有竞争条件(但没有,除非你添加HOLDLOCK
,就像Dan Guzman的帖子所演示的那样),我仍然觉得最好坚持老式的,独立的插入/更新方法。主要原因不是语法难学(事实确实如此),或者很难解决并发问题(事实并非如此),而是有几个未解决的错误——即使在SQL Server 2012中仍然存在——涉及到这个操作。我在这篇文章中指出了十几个谈论最近已经修复的另一个MERGE
错误的人。我还在这里发布了一个警示性提示,并在这里加入了其他几个提示。
正如我在评论中建议的那样,我不想发出天要塌下来的警报,但我真的对切换到MERGE
不那么感兴趣,直到活跃的bug少得多。因此,我建议现在坚持使用老式的UPSERT
,即使您使用的实际语法可能不是您遇到的性能问题的根源。
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
);
对于性能问题,您需要查看会话的等待时间(Plan Explorer*可以帮助您,通过为您启动扩展事件会话),或者至少在查询运行时sys.dm_exec_requests
中的blocking_session_id
和wait_type_desc
。
*免责声明:我曾经为SQL Sentry工作。