我有一个存储过程,该过程目前对 TempDb 的影响很大,这使得查询运行速度很慢,有时会消耗大量磁盘空间(不断增长的 TempDb)。我正在获取这样的数据:
ID StartDate EndDate
----------- ----------------------- -----------------------
1 2013-06-17 00:09:59.270 2013-09-25 00:09:59.270
2 2013-06-22 00:10:30.077 2013-07-22 00:10:30.077
并且需要根据源数据的范围将其按项目(ID)、年份和月份进行分组,并计算每月的天数,希望以这个结束(减去我的深夜计算错误):
ID TheYear TheMonth NumberOfDays
--- ------- ----------- ------------
1 2013 6 14
1 2013 7 31
1 2013 8 31
1 2013 9 25
2 2013 6 9
2 2013 7 22
今天,这个计算是使用一个类似于这个的存储过程来完成的:
INSERT INTO GroupedData
(
ID,
TheYear ,
TheMonth ,
NumberOfDays
)
SELECT ID,
YEAR(StartDate + v.number) AS TheYear,
MONTH(StartDate + v.number) AS TheMonth,
COUNT(*) AS NumberOfDays
FROM dbo.RawData
INNER JOIN
master..spt_values v ON v.type = 'P'
AND v.number <= DATEDIFF(d, StartDate, EndDate)
GROUP BY ID,
YEAR(StartDate + v.number),
MONTH(StartDate + v.number)
现在,这似乎在计算方面工作得很好,但它的性能不是很好。它消耗大量磁盘 (TempDb) 和 CPU 资源。输入表介于 100'000 到一百万行之间。实际来源日期范围低于 50 年,通常为 5-10 年。
我的猜测是使用 Tally 表 ( master..spt_values
) 连接会导致查询超出比例。注意:我在实际代码中使用生成的“数字”表来处理 Tally 表仅包含 2048 个条目的事实。
那么,有没有更好的方法来做这个计算呢?光标?CTE?临时表?其他魔法?