合并语句中的性能问题



我有一个像下面这样的合并语句

    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_idwait_type_desc

*免责声明:我曾经为SQL Sentry工作。

最新更新