SQL:将行折叠为总和[性能]

时间:2014-08-13 00:43:22

标签: sql sql-server performance sql-server-2008-r2 subquery

首先,我对我的问题有一个完美的解决方案,它还不够快。

我的数据是每小时计时卡,一次一周。

create table WeeklyHours
(
    Id int identity(1,1) not null,
    ResourceID int not null,
    WeekOf datetime not null,
    Sunday decimal(8, 5) not null,
    Monday decimal(8, 5) not null,
    Tuesday decimal(8, 5) not null,
    Wednesday decimal(8, 5) not null,
    Thursday decimal(8, 5) not null,
    Friday decimal(8, 5) not null,
    Saturday decimal(8, 5) not null,
    Total decimal(8, 5) not null,
    BufferFor int null,
)

我们的系统允许的是,如果一个人生病了,另一个人可以为他们填写。这称为缓冲。 BufferFor字段将是被覆盖的人的ResourceID,如果他们是正常工作时间,则为NULL。

我想要做的是将缓冲的行折叠到正常工作时间内。 (我们承认会有一个正常的工作时间排,即使它都是0)

我是这样做的(表格按日期范围内的适用行过滤掉):

select 
    WH.ResourceID, 
    WeekOf, 
    Monday + ISNULL((select SUM(Monday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as M, 
    Tuesday + ISNULL((select SUM(Tuesday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as T, 
    Wednesday + ISNULL((select SUM(Wednesday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as W, 
    Thursday + ISNULL((select SUM(Thursday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as R, 
    Friday + ISNULL((select SUM(Friday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as F, 
    Saturday + ISNULL((select SUM(Saturday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as S, 
    Sunday + ISNULL((select SUM(Sunday) from WeeklyHours WH2 where WH2.BufferFor = WH.ResourceID and WH2.WeekOf = WH.WeekOf),0) as U,
from
    WeeklyHours WH
where 
    WH.WeekOf >= @applicableMonday
    and WH.WeekOf <= @lastDay

我在Id上有一个群集主键。

我在ResourceID,WeekOf上有一个非聚集索引,对于子选择也有Mon-Sun小时和BufferFor

这方面的性能还可以,不是很糟糕,但也不是很好。运行我的Func的总成本约为.2019秒。此查询大约占我的Func总成本的65%,并且仅返回~5500行(在我过滤掉缓冲行之后)。但是,由于这最终被另一个过程调用了〜2000次,最终导致我耗费了大约7分钟。

有更快的方法吗? 谢谢!

1 个答案:

答案 0 :(得分:3)

你的表现非常好。你提到的问题是,你被滥用,听起来像编码不好。所以,让我们说你设法将查询的性能提高了90%,并且在sproc开始调用你的查询20,000次之后不久......你回到了你开始的地方。

我首先要研究问题,以确定在短时间内是否有比数千个电话更好的解决方案。作为一个简单的例子,可能是一个不从循环调用查询的简单修复。客户端代码也可以使用缓存,而不是针对不会发生太大变化的数据重复调用查询。

如果你想遵循表现路线,那么我会建议去正规化。由于您的查询结果按周分组,因此非规范化实际上是一个很好的解决方案。您将创建另一个表并使用查询结果填充它...您也不会一直调用tour子查询。 SQL Server通常会对此进行优化,但它肯定值得尝试。

祝你好运。