1

我有一个如下的合并语句

    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 秒即可执行。但是对于第二组记录(大约 300,000 条),它需要一个多小时。

两天前,我已经加载了 50 个这样的集合,并且相同的查询运行得非常快,但从今天开始它非常慢。我不知道出了什么问题。

注:查询

从 TABLEA 中选择 WITH(NOLOCK) INNER JOIN TableB .....

在所有场景中需要 20 秒。

4

1 回答 1

4

虽然MERGE语法更好,并且它似乎承诺更好的原子性和没有竞争条件(但除非你添加,否则不会HOLDLOCK,正如 Dan Guzman 的这篇文章所展示的那样),我仍然觉得坚持旧式更好,单独的插入/更新方法。主要原因不是语法难学(确实如此),或者难以解决并发问题(事实并非如此),而是存在几个未解决的错误 - 即使在 SQL Server 2012 中也是如此仍然 - 涉及此操作。我在这篇文章中指出了其中的十几个,它们谈到了MERGE最近修复的另一个错误。我还在此处发布的警告提示中详细介绍了和其他几个人在这里插话。

正如我在评论中所建议的那样,我不想发出天要塌下来的警报,但我真的对切换到没有那么感兴趣,MERGE直到有更少的活动错误。所以我建议现在坚持使用老式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 Explorerblocking_session_id * 可以通过为您启动扩展事件会话来帮助解决此问题),或者至少wait_type_descsys.dm_exec_requests查询运行时进行。

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

于 2013-03-11T19:25:30.877 回答