0

我有一个存储过程,该过程目前对 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?临时表?其他魔法?

4

1 回答 1

0

尝试这个

     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
于 2013-06-16T23:00:29.827 回答