2013-05-01 116 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