[英]SQL Server 2005 performance issue with DISTINCT
我有一個表tblStkMst2
,它具有87列和53,000行。 如果執行以下查詢,則需要83到96毫秒(Core2 Duo,2.8 GHz,2 GB RAM)。 但是,當我使用一個獨特的關鍵字時,它需要1086到1103毫秒(超過1秒)。 真的很貴。 如果我對53,000行數據應用重復刪除算法,則不會花費1秒。
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)
並不是說DISTINCT是非常昂貴的(只有53000行,這很小)。 您會看到明顯的性能差異,因為添加DISTINCT時SQL Server選擇了完全不同的查詢計划。 沒有看到查詢計划,很難看到正在發生的事情。
您的查詢中有幾件事可以做得更好,但可以顯着提高性能。
(1)避免在需要轉換列的地方使用諸如此類的where子句:
AND (MONTH(tblStkMst2.SIssDate) = @monthOnly) AND (YEAR(tblStkMst2.SIssDate) = @yearOnly)
如果您在SIssDate列上有一個索引,SQL Server將無法使用它(它可能會進行表掃描,因為我懷疑它將無法使用另一個索引)。
如果要利用SIssDate索引,最好嘗試將@ monthOnly / @ yearonly參數轉換為最小日期和最大日期,並在查詢中使用它們:
AND (tblStkMst2.SIssDate between @minDate and @maxDate);
如果表上有代理主鍵(即聚集索引),則在運行查詢之前執行此操作可能很有用(假設代理主鍵稱為tblStkMst2_id)
SELECT @minId=MIN(tblStkMst2_id), @maxId=(tblStkMst2_id)
FROM
tblStkMst2 WHERE tblStkMsg2.SIssDate between @minDate and @maxDate;
這應該非常快,因為SQL Server甚至不需要查看表(只需查看SIssDate非聚集索引和tblStkMst2_id聚集索引)。
然后,您可以在主查詢中執行此操作(而不是日期檢查):
AND (tblStkMst2.tblStkMst2_id BETWEEN @minId and @maxId);
使用聚集索引比使用非聚集索引要快得多,因為數據庫將能夠順序訪問這些記錄(而不是通過非聚集索引重定向)。
(2)將連接延遲到tblStkMst2,直到執行DISTINCT(或GROUP BY)之后。 DISTINCT(GROUP BY)中的條目越少越好。
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-不要使用DISTINCT
2-在TblSModelMst(SMNo) INCLUDE (Vehicle)
上創建索引,並為其他JOIN
鍵建立索引。
您確實應該弄清楚為什么要得到重復的副本並首先要照顧它。 一個或多個JOIN
ed表中可能有其他匹配行。
DISTINCT
有它的地方,但在很大程度上過度使用晦澀的數據問題,這是一個非常昂貴的操作,尤其是當你有大量你是從篩選下來的行。
要獲得更完整的答案,您需要解釋您的數據結構以及您要實現的目標。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.