2011-08-15 39 views
7

我有一個特殊的SQL查詢,似乎遭受了一個神祕的性能問題。下面是該查詢:需要使用聚合函數來提高SQL查詢的性能

SELECT COUNT(LengthOfTime) AS TotalTime, 
     SUM(LengthOfTime) AS TotalLength, 
     SUM(LengthOfTime)/COUNT(LengthOfTime) AS AverageTime, 
     SUM(Pops)/COUNT(LengthOfTime) AS AveragePop 
    FROM ((SELECT * 
      FROM (SELECT *, ID & YearRec AS ID2 
        FROM MyFirstTable 
       UNION ALL 
       SELECT *, ID & YearRec AS ID2 
        FROM Table2011) AS TEMP 
      WHERE STARTTIME >= '8/1/2011 00:00:00' 
      AND StartTime <= '8/5/2011 23:59:59') AS TEMP2 
    JOIN AppleTable ON TEMP2.Reason = AppleTable.Skills) 
    JOIN PeopleTable ON TEMP2.Operator = PeopleTable.Operators 
WHERE AppleTable.[ON] = 1 
    AND PeopleTable.[ON] = 1 
    AND Rec_Type = 'SECRET AGENT' 

這裏的問題是,這個查詢運行速度很快(0:00至0:02),當5天跨度運行,但速度很慢(1:20至1:45 )爲期6天。

表中每天約有105,000條記錄(MyFirstTable和Table2011)。

我的問題:有沒有上限,你看到在SQL Server中的一個嚴重的性能問題之前,你可以通過聚合函數的行數? (目前使用的是2008 R2)

+0

是您的統計數據,您是否最近重新編制了索引? –

+0

您的聲音可能會從內存操作溢出到需要磁盤的操作。我不熟悉MySQL調優細節,但是如果有臨時工作區的內存分配參數,可以嘗試增加它。 –

+1

@Jim:它不是mySQL ... –

回答

4

不,沒有預定義的聚合函數上限。

在性能上的偏斜可能受下列一種或多種:

  • 舊的和/或不適合的索引結構
  • 緩存執行計劃
  • 緩存數據
  • 數據大小不是統一(前五天是10行,第六是100 B行)

您可以運行查詢在SSMS中查看實際的執行計劃。這將告訴你運行查詢的成本最高的地方,這將幫助你確定最佳的行動方案。

編輯基於評論:

如果沒有在Table2011包含[STARTTIME]索引,然後創建一個。如果有索引,但它被忽略,那麼你必須弄清楚爲什麼。如果分解,那麼重建索引肯定會有幫助。下面是如何重建

ALTER INDEX [YourIndexName] ON [dbo].[Table2011] REBUILD WITH (STATISTICS_NORECOMPUTE = ON);

或者你可以在SSMS做到這一點 - 瀏覽到對象瀏覽器中的具體指標,右擊並重建。

+0

我看着實際的執行計劃。 97%的成本來自Table2011的「表掃描」。這是我在UNION之前預測開始時間 – dan042988

+0

@ dan042988回答更新 –

+0

謝謝您指引我正確的方向。我結束了使用的實際執行計劃,以創建新的索引 使用'[數據庫名] GO 創建非聚集索引[QueryIndex1] ON [DBO]。[Table2011]([Rec_Type],[開始時間]) 包括:([運算符],[LengthOfTime],[Pop],[Reason]) GO' – dan042988

9

簡短回答:不,不會有一些魔術數量的記錄會導致MSSQL開始表現不佳。

現在,有可能查詢不會很好地擴展,結果是數據集越大,[指數級]越差。

您將遇到的一個大問題是您在預測 UNIONED語句後的StartTime 。相反,嘗試在UNION之前的兩次選擇中進行預測。這應該會產生巨大的差異,特別是如果您在StartTime上對兩個表格進行索引(在這些表格上生成索引查找)。

SELECT * FROM (
SELECT *, ID & YearRec AS ID2 FROM MyFirstTable 
    WHERE STARTTIME >= '8/1/2011 00:00:00' 
    AND STARTTIME <= '8/5/2011 23:59:59' 
UNION ALL SELECT *, ID & YearRec AS ID2 
FROM Table2011 
    WHERE STARTTIME >= '8/1/2011 00:00:00' 
    AND STARTTIME <= '8/5/2011 23:59:59' 
) AS TEMP 

您也許可以對代碼進行一些額外的重構。

+0

+1 - 關於WHERE位置的很好的一點。 –

+0

我會給+1發現'UNION'的位置。如果它可以進一步移出(將兩個表分開連接到另一個並分組,然後使用聚集體),則可能會進一步提高性能。您最終可能甚至不需要UNION,只使用'countFromSubquery1 + countFromSubquery2 AS TotalTime'等。 –

+0

對不起,但查詢優化器應處理此問題 - 查詢計劃應顯示此條件是否應用於子外部聯盟。應該使ZERO在性能上有所不同。 – TomTom