常规SQL查询性能

时间:2015-05-21 18:55:00

标签: sql sql-server performance tsql

我有一个很大但很苗条的桌子,记录了在活动上花费的时间。

两个表存在Activities和RecordedTime。记录时间包含一个日期标记,表示花费的时间。

我需要获取一个活动列表,这些活动只会在日期范围内记录时间。

目前我有代码构建排除列表并将这些活动存储到临时表中:

DECLARE @DontInclude TABLE (ActivityID INT)

INSERT INTO @DontInclude
 SELECT DISTINCT ActivityID
 FROM RecordedTime
 WHERE DateStamp < @StartDate

INSERT INTO @DontInclude
 SELECT DISTINCT ActivityID
 FROM RecordedTime
 WHERE DateStamp > @EndDate

这样做的问题是很多数据都在小日期范围之外,因此很长时间。

我无法使用BETWEEN,因为它没有带回 ONLY 在特定日期范围内记录时间的活动。

我查看了估算执行计划并创建了SQL建议的任何索引。

我的SP部分仍然是瓶颈。可以建议我可以改进其他哪些改变吗?

3 个答案:

答案 0 :(得分:2)

您想要的查询听起来像这样:

select a.*
from activities a
where not exists (select 1
                  from RecordedTime rt
                  where rt.activityId = a.activityId and
                        dateStamp < @StartDate
                 ) and
      not exists (select 1
                  from RecordedTime rt
                  where rt.activityId = a.activityId and
                        dateStamp > @EndDate
                 ) and
      exists (select 1
              from RecordedTime rt
              where rt.activityId = a.activityId 
             );

为了提高性能,您需要RecordedTime(activityId, datestamp)上的索引。

请注意,使用三个子查询是非常有意的。每个子查询都应该最佳地使用索引,因此查询应该相当快。

答案 1 :(得分:0)

您可以将insert语句组合成一个查询,以使其更有效:

DECLARE @DontInclude TABLE (ActivityID INT)

INSERT INTO @DontInclude
 SELECT DISTINCT ActivityID
 FROM RecordedTime
 WHERE DateStamp < @StartDate OR Datestamp > @EndDate

当然,就像@Gordon Linoff所提到的那样,在recordedtime表上添加一个非聚集索引会使它更快!

答案 2 :(得分:0)

如何首先收集范围内的列表,然后删除应排除的列表:

SELECT DISTINCT tmpId = r.ActivityID
INTO #tmp
FROM RecordedTime r
WHERE r.DateStamp >= @StartDate and r.DateStamp < @EndDate

DELETE FROM #tmp
WHERE exists(select 1 from RecordedTime r 
             where r.ActivityID = tmpID
             and (r.DateStamp < @startDate or
                  r.DateStamp > @endDate))

这应该更快,因为您只检查可能包含的条件的排除条件(“不存在”);而不是在表中的所有内容上运行“不存在”。