2013-12-12 141 views
0

我正在尋找一種方法來改進以下查詢。SQL Server 2012 - 提高查詢性能

它收集的是有任何組織在2013年

會員我已經能夠確定,在此查詢子查詢是真正的性能殺手組織的成員,但我無法找到一種刪除子查詢並使結果表正確的方法。

該查詢僅收集此日曆年中具有成員資格的人員的所有「PersonID」和「MemberId」。但是,一個日曆年可能有兩個會員資格。如果發生這種情況,那麼我們只想選擇您在該日曆年中擁有的最後成員資格:這就是子查詢的用途。

「WorkingYear」與日曆年不同。例如,工作年份可以是一整年,但也可以從2013年9月到2014年9月運行。這就是爲什麼我指定的workingyear已啓動或在2013年

這到底是查詢:

SELECT DISTINCT PersonID, 
       m.id AS MemberId 
FROM Members AS m 
     INNER JOIN WorkingYears AS w 
     ON m.WorkingYearID = w.ID 
      AND (YEAR(w.StartDate) = 2013 
        OR YEAR(w.EndDate) = 2013) 
WHERE m.Id = (SELECT TOP 1 m2.id 
       FROM DBA_Member m2 
       WHERE personid = m.PersonID 
         AND ((droppedOut = 'false') 
          OR (droppedOut = 'true' 
            AND (yeardropout = 2013))) 
       ORDER BY m.StartDate DESC) 

此查詢應收集有關50.000行對我來說,這樣顯然也是在執行子查詢至少50,000次,我正在尋找一種方法來避免這種情況。有沒有人有任何想法可以讓我指出正確的方向?

JOINT中使用的所有字段都應正確編制索引。 'droppedOut'(位),'yeardropout'(int)還有一個單獨的索引。我也同時在兩個領域創建了一個索引,但無濟於事。

在執行計劃中,我看到一個「eager spool」正在發生,佔用了60%的查詢時間。它有一個Member.ID,Member.DroppedOut,Member.YearDropout的輸出列表,這些都是我在子查詢中使用的所有字段。此外,它得到50.500 rebinds。

有沒有人有任何建議?

+1

是工作一年始終是12個月?即從開始日期可預測的結束日期?你也可以上傳XML實際查詢計劃嗎? 'DBA_Member'有多少行? –

回答

2

你只需要做的子查詢一次,如果你使用CTE

WITH subQall AS 
(
    select id, personID, 
      ROW_NUMBER() OVER (PARTITION BY personID ORDER BY StartDate DESC) as rnum 
    from DBA_Member 
    WHERE (droppedOut='false') OR (droppedOut='true' AND (yeardropout = 2013)) 
), subQ AS 
(
    select id, personID 
    from subQall 
    where rnum = 1 
) 
SELECT DISTINCT PersonID, m.id as MemberId 
FROM Members AS m 
INNER JOIN WorkingYears AS w ON m.WorkingYearID = w.ID 
JOIN subQ ON m.ID = subQ.ID and m.personID = subQ.personID 
WHERE StartDate BETWEEN '1-1-2013' AND '12-31-2013' 
+0

出於興趣,會對範圍進行檢查WHERE子句中的日期不會比使用YEAR函數更快? – Bridge

+0

@Bridge - 我的想法。儘管如此,這與OP中的查詢不同。對於每組最大n沒有任何邏輯。 –

+0

@MartinSmith - 好點,固定。 – Hogan

0

你可以嘗試聯接而不是子查詢嗎?

這樣

SELECT DISTINCT PersonID, m.id as MemberId 
FROM Members AS m 

INNER JOIN WorkingYears AS w ON m.WorkingYearID = w.ID 
AND (year(w.StartDate) = 2013 OR year(w.EndDate) = 2013) 

JOIN (select top 1 m2.id ID from DBA_Member m2 where personid= m.PersonID 
     and ((droppedOut='false') OR (droppedOut='true' AND (yeardropout = 2013))) 
     order by m.StartDate desc) Member ON m.Id = Member.ID 
+0

這似乎將需要更多的時間,因爲在執行子查詢後進行JOIN,因此在OP查詢中....您並未消除您正在將其他操作添加到查詢中的子查詢 – Rafael