4

私は次のクエリを持っています:

SELECT fpa.scenario_id,
   fpa.facility_id,
   cge.CostGroupId result_total_id,
   mp_surrogate_id,
   CAST(SUM(fpa.raw_amount * cge.CostSign) AS DECIMAL(25, 13)) 
   result_total_amount         
INTO ADM_FactProfitTotalAmount_1
FROM #tempAmount fpa
JOIN ResultTest cge ON cge.CostId = fpa.process_id 
WHERE fpa.scenario_id = 1
GROUP BY fpa.scenario_id, fpa.facility_id, cge.CostGroupId, fpa.mp_surrogate_id
  • 私には2#tempAmount億2000万行あります。
  • 私にResultTestは150行あります。

私はインデックスを持っています#tempAmount

CREATE NONCLUSTERED INDEX #tempAmount_process_id
ON  #tempAmount(scenario_id, facility_id, mp_surrogate_id, process_id )

実行には約1時間かかります。それを最適化することは可能ですか?

編集:

ResultTest列CostIdにインデックスを作成し、他のインデックスとクエリを少し変更しました

    CREATE CLUSTERED INDEX #tempFactAmount_index 
    ON  #tempAmount (process_id ,facility_id, mp_surrogate_id )

    SELECT  ISNULL(CAST(1 as BIGINT), 0) scenario_id,
            fpa.facility_id,
            cge.CostGroupId result_total_id,
            fpa.mp_surrogate_id,
            CAST(SUM(fpa.raw_amount * cge.CostSign) AS DECIMAL(25, 13)) result_total_amount         
    INTO ADM_FactProfitTotalAmount_1
    FROM ResultTest cge
    JOIN #tempAmount fpa ON cge.CostId = fpa.process_id 
    GROUP BY fpa.facility_id, fpa.mp_surrogate_id, cge.CostGroupId

実行計画:

41%がADM_FactProfitTotalAmount_1に挿入

51%ハッシュマッチ集計

2%ハッシュマッチ内部参加

4

3 に答える 3

2

このようなシナリオでは、小さなテーブルに参加する前に、大きなテーブルの金額を合計すると役立つことがよくあります。したがって、この場合、次を使用します。

;WITH SUMCTE
AS
(
SELECT      fpa.facility_id,
            fpa.mp_surrogate_id,
            fpa.process_id,
            SUM(fpa.raw_amount) AS total_amount         
    FROM #tempAmount fpa 
    GROUP BY fpa.facility_id, fpa.mp_surrogate_id, fpa.process_id
)
SELECT  CAST(1 as BIGINT) AS Scenario_id,
        facility_id,
        cge.CostGroupId result_total_id,
        mp_surrogate_id,
        CAST(SUM(SCT.total_amount * cge.CostSign) AS DECIMAL(25, 13)) result_total_amount         
    INTO ADM_FactProfitTotalAmount_1
    FROM ResultTest cge
    JOIN SUMCTE SCT ON cge.CostId = SCT.process_id 
    GROUP BY fpa.facility_id, fpa.mp_surrogate_id, cge.CostGroupId

process_id ごとに ResulTest に行が 1 つしかない場合は、次のようにして外側のグループを削除することでさらに単純化します。

;WITH SUMCTE
AS
(
SELECT      fpa.facility_id,
            fpa.mp_surrogate_id,
            fpa.process_id,
            SUM(fpa.raw_amount) AS total_amount         
    FROM #tempAmount fpa 
    GROUP BY fpa.facility_id, fpa.mp_surrogate_id, fpa.process_id
)
SELECT  CAST(1 as BIGINT) AS Scenario_id,
        facility_id,
        cge.CostGroupId result_total_id,
        mp_surrogate_id,
        CAST((SCT.total_amount * cge.CostSign) AS DECIMAL(25, 13)) result_total_amount         
    INTO ADM_FactProfitTotalAmount_1
    FROM ResultTest cge
    JOIN SUMCTE SCT ON cge.CostId = SCT.process_id 
于 2012-12-06T11:13:47.167 に答える
1
  • 推定実行計画を確認することから始めることをお勧めします。
    http://msdn.microsoft.com/en-us/library/ms191194.aspx

  • 複数列のインデックスは、プレフィックスを付けたままにしておく場合にのみ使用できます。 http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html

    そのため、process_id を scenario_id の隣に移動することをお勧めします。これらは where と join で使用されるためです。

    CREATE NONCLUSTERED INDEX #tempAmount_process_id ON #tempAmount(scenario_id, process_id, facility_id, mp_surrogate_id)

  • 最後の 1 つは、OS がディスク ブロックをできるだけ多くメモリにキャッシュできるようにすることです。Linux では、パフォーマンスが重要なデータベースを本番環境に置く前に、"cat your_database.store.file > /dev/null" を実行します。多くのディスク読み取りがメモリ キャッシュからヒットします。

于 2012-12-05T11:43:04.893 に答える
1

まず、実際の実行計画をキャプチャすることをお勧めします。SQL Server Management Studio (SSMS) からクエリを実行している場合は、[実際の実行計画を含める] オプションをオンにします。このクエリが別のプログラムから実行されている場合は、SQL Server プロファイラーを実行し、Showplan Statistics Profile や Showplan XML Statistics Profile をオンにします。このプロファイルを確認して、クエリが期待どおりに動作しているかどうかを確認します。

ResultTest カラム CostId にインデックスはありますか? 150 行しかないため、このテーブルのインデックス スキャンは大したことではありません。このテーブルにインデックスがない場合は、試してみてください。

実行計画がネストされたループを実行して ResultTest に参加しているのではないかと思います。もしそうなら、それは 150 X 220,000,000 = 330 億の操作になります。この場合、ハッシュ結合またはマージ結合のパフォーマンスが大幅に向上します。結合ヒントOPTION (HASH JOIN)またはOPTION (MERGE JOIN). これだけで、大きな違いを生むことができます。

#tempAmount のインデックスには、クエリに不要な列が多数含まれていSELECTます。また、NONCLUSTEREDインデックスです。CLUSTERED インデックスもありますか? そうでない場合は、それを変換してCLUSTERED、他の列を取り除くことができます。scenario_id のすべての行が連続するため、これによりインデックスのサイズが小さくなり、パフォーマンスが向上します。

于 2012-12-05T14:05:05.763 に答える