簡體   English   中英

SQL Server 2005的DISTINCT性能問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM