4

次のようなテーブルがあります。

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 クエリのパフォーマンスを達成するためのより良い方法はありますか?

EDIT 1:テーブルのサイズに注意する必要があります。平均して、ソースには常に平均で 30 ~ 70 行が含まれ、ターゲットには 3,000 万行を超える行が含まれます。

4

3 に答える 3

4

検討します

WHEN MATCHED AND ValueA <> Value THEN

必要のないレコードを更新している可能性があります。

于 2013-05-23T19:41:41.620 に答える
3

参考までにこちらです。クエリを改善するために使用した関連するポイントがいくつかあります。

  • @HLGEM によって提案された最適化を使用します。それは完全に理にかなっています。
  • ここのMSDN記事からの2つの関連ポイント

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 に答える