2013-05-01 201 views
2

我正在使用ms sqlserver 2005.我有一個查詢需要根據日期進行過濾。 可以說我有一個包含電話號碼和日期的表格。 我需要提供時間範圍內電話號碼的計數(開始日期和結束日期)。 如果這些電話號碼在過去出現,則不應將其計入結果計數。 我做這樣的事情:SQL查詢選擇優化

select (phoneNumber) from someTbl 
where phoneNumber not in (select phoneNumber from someTbl where date<@startDate) 

這看起來效率不高,在所有我(和它花費過多時間瓶坯與一些副作用,也許應該在不同的問題,提交的結果) 我在某些TBL中有大約300K行,應該檢查。

我做這個檢查後,我需要檢查一件事。 我有一個過去的數據庫,其中包含另一個30K的電話號碼。 所以我加入

and phoneNumber not in (select pastPhoneNumber from somePastTbl) 

和真正釘棺材或打破駱駝或什麼都使用的是解釋致命狀態短語的最後一根稻草。

所以我正在尋找更好的方法來預製這2個動作。


UPDATE 我已經選擇去亞歷山大的解決方案,結束了這種查詢:

SELECT t.number 
FROM tbl t 
WHERE t.Date > @startDate 
--this is a filter for different customers 
AND t.userId in (
        SELECT UserId 
        FROM Customer INNER JOIN UserToCustomer ON Customer.customerId = UserToCustomer.CustomerId 
        Where customerName = @customer 
       ) 
--this is the filter for past number 
AND NOT EXISTS (       
        SELECT 1 
        FROM pastTbl t2 
        WHERE t2.Numbers = t.number        
       ) 
    -- this is the filter for checking if the number appeared in the table before startdate    
AND NOT EXISTS (       
        SELECT * 
        FROM tbl t3 
        WHERE t3.Date<@startDate and t.number=t3.number 
       ) 

感謝吉拉德

+1

什麼部分查詢的花費最多時間的查詢執行計劃?索引是否提供?查詢需要多長時間?什麼是可接受的時間範圍? – jpw 2013-05-01 09:56:01

回答

1

還有一個選項

SELECT t.phoneNumber 
FROM SomeTbl t 
WHERE t.date > @startDate 
    AND NOT EXISTS (       
        SELECT 1 
        FROM SomePastTbl t2 
        WHERE t2.phoneNumber = t.phoneNumber        
       ) 
+0

嗨亞歷山大,感謝您的簡單解決方案。我採用了你的方法,在另一個需要完成的過濾中使用NOT EXISTS。我會接受你的答案,雖然它不完整,但它是真正的複製粘貼,以完成它與我需要的不同的過濾器。謝謝 – gilad 2013-05-01 14:20:07

+0

沒問題;)... – 2013-05-01 14:27:16

2

因爲它是一個不只是開關小於一個大於。

select phoneNumber from someTbl where date > @startDate 

下一頁濾除somePastTbl

select s1.phoneNumber from someTbl s1 
LEFT JOIN somePastTbl s2 on s1.phoneNumber = s2.phonenumber 
where s1.date > @startDate and s2 IS NULL 

UPDATE

按照評論:

於開始日期的月份

SELECT COUNT(s1.phoneNumber) FROM someTbl s1 
LEFT JOIN somePastTbl s2 on s1.phoneNumber = s2.phonenumber 
where DATEADD(MONTH,-1,@startDate) < s1.date AND s1.date < @startDate and s2 IS NULL 
+0

嗨。以快速響應。我已經使用了關於舊數據的第二個陳述,它確實提高了性能。 – gilad 2013-05-01 10:49:13

+0

嗨。以快速響應。我已經使用了關於舊數據的第二個陳述,它確實提高了性能。然而,第一個條件沒有得到滿足。我需要檢查在請求的時間範圍內出現的電話號碼(可以在上個月說+12127773456)也不存在之前(如果我在+12127773456之前2個月也不應該計算它在當前的發生次數計數)。希望我讓自己更清楚。感謝 – gilad 2013-05-01 10:55:05

+0

@gilad所以如果我明白你需要知道它的存在時間不到一個月的開始日期? – AbstractChaos 2013-05-01 14:08:39

1

一個簡單的索引

CREATE NONCLUSTERED INDEX IX_SomeTbl_date_phoneNumber 
    ON SomeTbl 
(
    date ASC, 
    phoneNumber ASC 
) 

然後

SELECT phoneNumber FROM SomeTbl WHERE date > @startDate 
EXCEPT 
SELECT phoneNumber FROM SomePastTbl; 
+0

感謝您的答覆。我已經在這張桌子上有這些索引。 – gilad 2013-05-01 10:45:54

+0

@gilad我只指定了一個覆蓋索引,這個聲明是否很快並且正在做你想要的? – Jodrell 2013-05-01 10:48:34

+0

當我使用它很簡單時,聲明很快。當我添加一些內部連接到第一個選擇來篩選userId它再次卡住。 – gilad 2013-05-01 11:30:25

1

你要電話號碼,其最低開始日期比你的開始日期。這建議在進行計數(或創建列表)之前在電話號碼級別進行聚合。

這裏有一種方法,與having子句中的條件:

select COUNT(*) 
from (select t.phonenumber, 
     from someTble t left outer join 
      somePastTble pt 
      on t.phonenumber = pt.phonenumber 
     where pt.phonenumber is null 
     having MIN(date) >= @startdate 
    ) t 

你也可以這樣寫利用窗口函數(SQL 2005或更高版本)。下面是使用min()版本:

select COUNT(distinct t.phonenumber) 
    from (select t.*, t.phonenumber, MIN(date) over (partition by phonenumber) as mindate 
     from someTble t 
     ) t left outer join 
     somePastTble pt 
     on t.phonenumber = pt.phonenumber 
    where pt.phonenumber is null and mindate >= @startdate 
+0

嗨。感謝你的努力。在第一個選項中(我會堅持下去 - 在學習新東西的時候學習新東西足夠了),沒有考慮數字是否在@startdate之前在db中,然後它不應該被計數。 – gilad 2013-05-01 14:05:54