2012-01-21 80 views
0

我有一個表tblStkMst2,它有87列和53,000行。如果我執行以下查詢,則需要83到96毫秒(Core2 Duo,2.8 GHz,2 GB RAM)。但是當我使用不同的關鍵字時,它需要1086到1103毫秒(超過1秒)。這真的很貴。如果我對53,000行數據應用重複刪除算法,則不需要1秒。DISTINCT SQL Server 2005性能問題

SQL Server 2005中有沒有其他的方法來提高執行時間?

declare @monthOnly int     set @monthOnly = 12 
declare @yearOnly int     set @yearOnly = 2011 

SELECT --(distinct)-- 

tblSModelMst.SMNo as [ModelID] 
,tblSModelMst.Vehicle as [ModelName] 

FROM tblStkMst2 

INNER JOIN tblDCDetail ON tblStkMst2.DCNo = tblDCDetail.DCNo AND tblDCDetail.Refund=0 
INNER JOIN tblSModelMst ON tblStkMst2.SMno = tblSModelMst.SMNo 
INNER JOIN tblBuyerMst ON tblDCDetail.BNo = tblBuyerMst.BNo 
LEFT OUTER JOIN tblSModelSegment ON tblSModelMst.SMSeg = tblSModelSegment.ID 
left outer JOIN dbo.tblProdManager as pd ON pd.PMID = tblBuyerMst.PMId 


WHERE (pd.Active = 1) AND ((tblStkMst2.ISSFlg = 1) or (tblStkMst2.IsBooked = 1)) 
    AND (MONTH(tblStkMst2.SIssDate) = @monthOnly) AND (YEAR(tblStkMst2.SIssDate) = @yearOnly) 
+0

您是否嘗試過使用調整顧問程序並顯示估算執行計劃。這些應該可以幫助你找到時間。你是否也有所有主鍵和外鍵列的索引? –

+1

請至少顯示'DISTINCT'版本的執行計劃,最好是兩者。 –

+0

@Abidul伊斯蘭教 - 如果你想繼續提供幫助,你需要回應他人。 –

回答

0

幾種方法。

1 - 不要使用DISTINCT

2 - TblSModelMst(SMNo) INCLUDE (Vehicle)創建索引和索引你的其他JOIN鍵。

你真的應該弄清楚爲什麼你會得到重複的東西,並照顧到第一個。在一個或多個JOIN ed表中可能會有其他匹配行。

DISTINCT有它的地方,但嚴重過度使用晦澀的數據問題,這是一個非常昂貴的操作,尤其是當你有大量你是從篩選下來的行。

爲了獲得更完整的答案,您需要解釋您的數據結構以及您試圖實現的目標。

1

SQL Server優化以避免最壞情況執行。這可能導致它更喜歡次優算法,比如偏好磁盤排序而不是散列排序,只是爲了安全起見。

對於有限數量的不同值,哈希排序是執行distinct操作的最快方式。哈希排序交易內存的執行速度。但是,如果您有大量值,則散列排序會因爲散列太大而無法存儲在內存中而崩潰。所以你需要一種方法告訴SQL Server這個散列符合內存。

一種可能的方式做到這一點是使用臨時表:

declare @t (ModelID int, ModelName varchar(50)) 
insert @t (ModelID, ModelName) select ...your original query here... 
select distinct ModelID, ModelName from @t 

SQL Server將知道臨時表的大小,允許其選擇在許多情況下,更好的算法。

+1

關於此的任何文檔? –

4

這不是說DISTINCT非常昂貴(這只是53000行,這很小)。您看到顯着的性能差異,因爲SQL Server在添加DISTINCT時正在選擇完全不同的查詢計劃。沒有看到查詢計劃,很難看到發生了什麼。

您的查詢中有幾件事情,但您可以做得更好,這可以顯着提高性能。

(1)避免在where子句這樣,你需要變換列:如果你有SIssDate列SQL Server上的索引將無法使用它

AND (MONTH(tblStkMst2.SIssDate) = @monthOnly) AND (YEAR(tblStkMst2.SIssDate) = @yearOnly) 

(它可能會做一個表掃描,因爲我懷疑它不能使用另一個索引)。

AND (tblStkMst2.SIssDate between @minDate and @maxDate); 

如果你想利用SIssDate指數的優勢,它如果你嘗試和@ monthOnly/@ yearonly參數轉換爲一個最小和最大日期,並在查詢中使用這些較好如果你有一個代理主鍵(這是聚集索引)在桌子上,它可能是有用的,這樣做你運行你的查詢(假設你的代理主鍵被稱爲tblStkMst2_id)之前

SELECT @minId=MIN(tblStkMst2_id), @maxId=(tblStkMst2_id) 
FROM 
tblStkMst2 WHERE tblStkMsg2.SIssDate between @minDate and @maxDate; 

這應該是非常快,因爲SQL服務器甚至不需要查看ta ble(僅在SIssDate非聚簇索引和tblStkMst2_id聚簇索引)。

然後你就可以在你的主查詢(而不是日期檢查)做到這一點:

AND (tblStkMst2.tblStkMst2_id BETWEEN @minId and @maxId); 

使用聚集索引比使用非聚集索引的數據庫將能夠順序更快訪問這些記錄(而不是通過非聚集索引重定向)。

(2)將連接延遲到tblStkMst2,直到執行DISTINCT(或GROUP BY)之後。 DISTINCT(GROUP BY)中的條目越少越好。

+0

+1我認爲通過刪除MONTH()和YEAR()調用來改變查詢將會對性能產生巨大的影響。 –