2012-12-05 57 views
4

我有以下查詢:優化長時間運行SQL Server查詢

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 
  • #tempAmount我有220個百萬行。
  • 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%哈希匹配內部加入

+1

你有一個指數'process_id'以及?從JOIN條件看,定義一個似乎是有益的。並且將'process_id'移動到第二個索引列也可能有所幫助。儘管沒有查詢計劃,但很難說明瓶頸在哪裏。 – Oded

+1

關於優化選擇好的網絡直播:http://www.brentozar.com/archive/2012/10/back-index-basics-how-make-select-statements-faster-video/ – Oded

+0

嘗試創建於#tempAmount聚集索引只是在scenario_id列上。 –

回答

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,因爲他們用在哪裏和加入。

    創建非聚集索引#tempAmount_process_id ON #tempAmount(scenario_id,PROCESS_ID,facility_id,mp_surrogate_id)

  • 最後一個:讓操作系統緩存磁盤塊的內存儘可能多的。在linux的 之前,一些性能關鍵的數據庫投入生產, 做「cat your_database.store.file>/dev/null」。 大量磁盤讀取將從內存緩存中命中。

1

首先,我會建議捕捉實際的執行計劃。如果您從SQL Server Management Studio(SSMS)運行查詢,請打開「包括實際執行計劃」選項。如果此查詢從另一個程序運行,請運行SQL Server Profiler並打開Showplan Statistics Profile和/或Showplan XML Statistics Profile。查看此配置文件,查看查詢是否按照您的預期運行。

你對ResultTest科拉姆CostId的指數?只有150行,這張表上的索引掃描不是什麼大問題。如果你在這張桌子上沒有索引,你可以試試。

不知是否執行計劃執行嵌套循環加入到ResultTest。如果是這樣,那將是150×220,000,000 = 330億次操作。如果是這種情況,散列連接或合併連接將會更好。您可以使用加入提示OPTION (HASH JOIN)OPTION (MERGE JOIN)強制特定加入。僅憑這一點就可以發揮巨大的作用。

上#tempAmount的指數有很多是沒有必要的SELECT查詢列。此外,它是一個NONCLUSTERED索引。是否還有一個CLUSTERED索引?如果不是,您可以嘗試將其轉換爲CLUSTERED並擺脫其他列。這將減小索引的大小,並且應該表現得更好,因爲scenario_id的所有行都是連續的。

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只有一排我會通過除去外組進一步簡化:

;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