我有一个很大但很苗条的桌子,记录了在活动上花费的时间。
两个表存在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部分仍然是瓶颈。可以建议我可以改进其他哪些改变吗?
答案 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))
这应该更快,因为您只检查可能包含的条件的排除条件(“不存在”);而不是在表中的所有内容上运行“不存在”。