2011-07-19 34 views
1

我的問題的基本要點是,對於每個事件A,我需要找到與同一用戶關聯的最早的以下事件B.目前,我有:在SQL中高效地查找下一個事件

SELECT e.UserID, e.date, min(e2.date) 
FROM Event e INNER JOIN 
    Event e2 ON e.UserID = e2.UserID AND e.date <= e2.date 
WHERE e.Event LIKE 'A' AND e2.Event LIKE 'B' 

然而,對於每一個事件A(它可以發生於用戶的任何次數),衆多的事件B的發生,所以內連接的創建無數額外行,這則有在min函數上除掉。有沒有更高效/更快的方式來做到這一點?

(服務器是MSSQL Server 2008中)

UPDATE: 難道更快以秩()?

Select UserID, date, date2 
from (
    Select e.UserID, e.date, e2.date as date2, rank() OVER (PARTITION BY e.date, e.UserID ORDER BY e2.date) as rank 
    FROM Event e INNER JOIN Event e2 on e.UserID = e2.UserID 
    WHERE e.Event = 'A' and e2.Event = 'B' and e.date <= e2.date 
) 
WHERE rank = 1 

或者將優化帶出來基本相等?

+0

使用'min'似乎對我很好。然而,有沒有一個原因是你使用'LIKE'而不是'='。這就是真正的業績下滑的地方。 –

+0

你不需要在那裏有一個「GROUP BY」嗎? –

+0

Jacob:我對SQL有點新,所以like和=有什麼不同呢? – Jodaka

回答

0

加入第三次是否更快?可能不會,但它可能值得嘗試。這裏,表格「e3」中返回的任何數據表示日期中的日期和e2日期之間的。所以我們加入了這個,並抓住了NULL的值。

SELECT e.UserID, e.date, e2.date 
FROM Event e 
INNER JOIN Event e2 ON (e.UserID = e2.UserID AND e.date <= e2.date) 
LEFT JOIN Event e3 ON (e.UserID = e3.UserID AND e.date <= e3.date AND e3.date <= e2.date AND e3.Event = 'B') 
WHERE e.Event = 'A' AND e2.Event = 'B' 
AND e3.date IS NULL 

我想這可能使用了相同的策略,你MIN查詢,但也許不是?我很想知道這兩種方式。

+0

我不知道爲什麼,但似乎工作速度非常快。我無法訪問IO統計數據,所以我無法確定。但我喜歡它。 – Jodaka

+0

如果它真的太好了,請確保它返回正確的數據!另請注意:請注意'e3.Event ='C''處於JOIN狀態。如果您將其移至WHERE條款,您將得到不正確的結果。如果你最終使用了這個答案,你可能想對此留言 - 如果你回過頭來給e2表添加更多條件,他們也需要放在'e3'表上。 –

+1

所以我跑了一些測試,如果ASP.NET的StopWatch是可靠的(它可能不是),這個方法是三個小數據集中最慢的(限制上個月的事件),但是最快的大數據集(限於過去四年)。我想所有的排序加起來可以減慢排名和最低版本? – Jodaka

0

這樣做的唯一更快的方法,我知道要求您在循環中處理每個事件A並使用單獨的查詢使用TOP和ORDER BY查找第一個事件B,該查詢允許它查看答案適合的指數。這可以在存儲過程中完成以獲得最大效率。