什么样的索引可以帮助我在这个MERGE查询中?

时间:2013-05-23 19:31:11

标签: sql sql-server sql-server-2008 query-optimization

我有一张这样的表:

Name | TimeA | TimeB | ValueA | ValueB

而且,我正在执行一些MERGE操作,如下所示:

  CREATE TABLE #TEMP1...

  INSERT INTO #TEMP1
  SELECT Name, Value
  FROM dbo.AnotherTable
  WHERE ...

  MERGE INTO dbo.MyTable AS Target
    USING (SELECT Name, Value FROM #TEMP1) AS Source
    ON Target.Name = Source.Name
    AND Target.TimeA = @TimeA
  WHEN MATCHED THEN
    UPDATE SET ValueA = Value
  WHEN NOT MATCHED THEN
    INSERT (Name, TimeA, TimeB, ValueA)
    VALUES (Source.Name, @TimeA, @TimeB, Value)

查询执行计划说明如下:

MERGE -> Table Merge 3% -> Compute Scalar 0% -> 
Top 0% -> Compute Scalar 0% -> Compute Scalar 0% ->
Nested Loops (Left Outer Join) 0% <- Constant Scan 0%
              ^
              |
              |
              --- Compute Scalar 0% <- Table Spool (Kager Spool) 12% <- Table Scan 86%

然而,该计划并没有告诉我索引会改善性能。我认为(Name,TimeA)上的非聚集索引应该可以提高性能。有没有更好的方法来实现这样的MERGE查询的性能?

编辑1 :我应该注意表格的大小。平均来源平均包含30-70行,而目标包含&gt; 3000万行。

3 个答案:

答案 0 :(得分:4)

我会考虑

WHEN MATCHED AND ValueA <> Value THEN

你可能正在更新不需要的记录。

答案 1 :(得分:3)

这是供参考。我用过一些相关的观点来改进我的查询:

  • 使用@HLGEM建议的优化。它完全有道理。
  • MSDN article here
  • 中的两个相关点
  

为了提高MERGE语句的性能,我们建议使用   遵循指数准则:

     
      
  • 在源表中的连接列上创建一个唯一且覆盖的索引。
  •   
  • 在目标表的连接列上创建唯一的聚簇索引。
  •   
  • 来自同一篇MSDN文章的另一点建议不要在查询中放置常量
  

要过滤掉源表或目标表中的行,请使用其中一个   以下方法。指定行过滤的搜索条件   适当的WHEN条款。例如,当没有匹配时   S.EmployeeName喜欢'%'然后插入....

因此,我添加的索引是:

ALTER TABLE #TEMP1
ADD CONSTRAINT PK_TEMP1 PRIMARY KEY CLUSTERED
(ELEMENTINSTANCE, ifAlias)

CREATE CLUSTERED INDEX IX_MyTable
ON dbo.MyTable(Name)

我最后的疑问是:

MERGE INTO dbo.MyTable AS Target
  USING (SELECT Name, Value FROM #TEMP1) AS Source
  ON Target.Name = Source.Name
WHEN MATCHED AND ValueA <> Value AND Target.TimeA = @TimeA THEN
  UPDATE SET ValueA = Value
WHEN NOT MATCHED THEN
  INSERT (Name, TimeA, TimeB, ValueA)
  VALUES (Source.Name, @TimeA, @TimeB, Value)

这给了我以下执行计划:

MERGE -> Table Merge 3% -> Compute Scalar 0% -> 
Top 0% -> Compute Scalar 0% -> Compute Scalar 0% ->
Nested Loops (Left Outer Join) 0% <- Table Scan (#TEMP1) Source 12%
              ^
              |
              |
              --- Compute Scalar 0% <- Clustered Index Seek (dbo.MyTable) 12%

谢谢大家的帮助!希望这应该保持一段时间的性能。

答案 2 :(得分:0)

我发现,通过花费大量时间创建没有提高性能的索引,当SSMS生成查询计划,并且不建议创建索引时,没有索引会有所帮助。情况并非总是如此,但往往是。

话虽如此,通过尝试一些索引,进入Profiler并检查一些指标,如总读数,可以很容易地解决问题。看看有什么帮助,有什么不帮助。如果没有看到完整的架构和各种表中的行数,我们就无法提供太多帮助。此外,我认为合并通常需要表扫描,没有索引可以帮助。