4

I have a table like this:

Name | TimeA | TimeB | ValueA | ValueB

And, I am performing some MERGE operations as follows:

  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)

The Query Execution Plan says the following:

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%

The plan, however does not tell me that an index will improve the performance. I'm thinking an unclustered index on (Name,TimeA) should improve performance. Is there a better way to achieve performance for MERGE queries like this?

EDIT 1: I should note the sizes of the tables. On an average Source always contains 30-70 rows on an average and Target contains > 30 million rows.

4

3 回答 3

4

我会考虑

WHEN MATCHED AND ValueA <> Value THEN

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

于 2013-05-23T19:41:41.620 回答
3

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

  • 使用@HLGEM 建议的优化。这完全有道理。
  • MSDN文章here的两个相关点

为了提高 MERGE 语句的性能,我们推荐以下索引指南:

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

要从源表或目标表中过滤掉行,请使用以下方法之一。在相应的 WHEN 子句中指定行过滤的搜索条件。例如,WHEN NOT MATCHED AND S.EmployeeName LIKE 'S%' THEN INSERT....

因此,我添加的索引是:

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%

谢谢你们每一个人的帮助!希望这应该保持性能一段时间。

于 2013-05-23T20:22:19.643 回答
0

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

话虽如此,您的问题可以很容易地通过尝试一些索引、进入 Profiler 并检查一些指标(如总读取数)来解决。看看什么有帮助,什么没有。如果没有看到完整的模式和各种表中的行数,我们就帮不上什么忙了。此外,我认为合并通常需要表扫描,而没有索引会有所帮助。

于 2013-05-23T19:36:24.563 回答