加快SQL Server中的累积总和计算

时间:2019-09-17 18:18:29

标签: sql sql-server running-total

作为一些解决方案构建的一部分,我必须实现一个正在执行总计(累计总和计算)的视图。我采用了最简单,最基本的方法来将表与具有日期列表的表连接起来,但看来视图仍然相当慢。即使表本身只有约15K行,在表上添加索引也无济于事。我想知道是否有人可以建议哪种方法可以加快速度?

有几个注意事项:

  1. 我需要计算直到特定ProjectIDContractorID为止的累积总和。因此对于同一日期,我可能会有很多ProjectID和ContractorId组合,但是Date,ProjectID和ContractorID的组合始终是唯一的

  2. 在主表中有日期,项目编号(但没有承包商编号),并且在此主日期表中我需要每个日期的累积总和,项目编号

  3. 我需要同时计算多个列的累计和,而不仅仅是一个

为了稍微介绍一下情况,我提供的表格是:

  • dbo.Project_Reporting_Schedule,其中包含projectid,日期的主列表。对于每种组合,我都需要根据另一张表计算累计和。请注意,它没有承包商!

  • Project_value_delivery是一个表,在该表中,我有一些实际值列用于执行累计和计算。它具有自己的日期集,该日期集可能与Project_Reporting_Schedule中的日期匹配,也可能不匹配,因此我们不能仅将表本身联接起来。另请注意,它具有Contractorid!

当前,我有以下选择,这是不言自明的,只是将表与具有主日期列表的表中的值连接起来并进行求和。 Select的效果很好,但是即使只有15K记录,它也要花5秒钟才能运行,这相当慢。

select 
    pv2.ProjectID,
    pv2.ContractorID,
    pv1.Date, 
    sum(pv2.ValuePlanned) as PlannedCumulative, 
    sum(pv2.ValueActual) as ActualCumulative,
    sum(pv2.MobilizationPlanned) as MobilizationPlanned,
    sum(pv2.MobilizationActual) as MobilizationActual,
    sum(pv2.EngineeringPlanned) as EngineeringPlanned,
    sum(pv2.EngineeringActual) as EngineeringActual,
    sum(pv2.ProcurementPlanned) as ProcurementPlanned,
    sum(pv2.ProcurementActual) as ProcurementActual,
    sum(pv2.ConstructionPlanned) as ConstructionPlanned,
    sum(pv2.ConstructionActual) as ConstructionActual,
    sum(pv2.CommisioningTestingPlanned) as CommisioningTestingPlanned,
    sum(pv2.CommisioningTestingActual) as CommisioningTestingActual
from 
    dbo.Project_Reporting_Schedule as pv1
join 
    dbo.Project_value_delivery as pv2 on pv1.Date >= pv2.Date and pv1.ProjectID = pv2.ProjectID
group by 
    pv2.ProjectID, pv2.ContractorID, pv1.Date

更新

为进一步说明,我将执行计划放在这里: https://www.brentozar.com/pastetheplan/?id=H12t-O1PS

创建的索引是相同的,在两个表上我都具有Projectid,Date组合以及ProjectID和Date列上的独立索引。

在适用的情况下,所有索引都是唯一非聚集索引;在适用的情况下,所有索引都是非聚集索引。

我们可以看到它执行了“非聚集索引查找”,这花费了大部分执行时间。也许索引需要调整?

2 个答案:

答案 0 :(得分:1)

好的,因此@Alex在注释窗口函数中的建议是一个可行的方法。与原始代码相比,下面的代码闪电般地运行:

select 
       pv2.ProjectID,
       pv2.ContractorID,
       pv1.Date, 
       sum(pv2.ValuePlanned) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as PlannedCumulative, 
       sum(pv2.ValueActual) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as ActualCumulative,
       sum(pv2.MobilizationPlanned) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as MobilizationPlanned,
       sum(pv2.MobilizationActual) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as MobilizationActual,
       sum(pv2.EngineeringPlanned) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as EngineeringPlanned,
       sum(pv2.EngineeringActual) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as EngineeringActual,
       sum(pv2.ProcurementPlanned) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as ProcurementPlanned,
       sum(pv2.ProcurementActual) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as ProcurementActual,
       sum(pv2.ConstructionPlanned) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as ConstructionPlanned,
       sum(pv2.ConstructionActual) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as ConstructionActual,
       sum(pv2.CommisioningTestingPlanned) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as CommisioningTestingPlanned,
       sum(pv2.CommisioningTestingActual) over (partition by pv2.ProjectID, pv2.ContractorID order by pv1.Date ROWS between unbounded preceding and current row) as CommisioningTestingActual
from 
       dbo.Project_Reporting_Schedule as pv1
       join dbo.Project_value_delivery as pv2 on pv1.Date = pv2.Date and pv1.ProjectID = pv2.ProjectID

答案 1 :(得分:0)

将比较从JOIN子句中取出,并将其移至WHERE子句:

select 
       pv2.ProjectID,
       pv2.ContractorID,
       pv1.Date, 
       sum(pv2.ValuePlanned) as PlannedCumulative, 
       sum(pv2.ValueActual) as ActualCumulative,
       sum(pv2.MobilizationPlanned) as MobilizationPlanned,
       sum(pv2.MobilizationActual) as MobilizationActual,
       sum(pv2.EngineeringPlanned) as EngineeringPlanned,
       sum(pv2.EngineeringActual) as EngineeringActual,
       sum(pv2.ProcurementPlanned) as ProcurementPlanned,
       sum(pv2.ProcurementActual) as ProcurementActual,
       sum(pv2.ConstructionPlanned) as ConstructionPlanned,
       sum(pv2.ConstructionActual) as ConstructionActual,
       sum(pv2.CommisioningTestingPlanned) as CommisioningTestingPlanned,
       sum(pv2.CommisioningTestingActual) as CommisioningTestingActual
       FROM
       dbo.Project_Reporting_Schedule as pv1
       join dbo.Project_value_delivery as pv2 on pv1.ProjectID = pv2.ProjectID
       WHERE pv1.Date >= pv2.Date
       GROUP BY pv2.ProjectID, pv2.ContractorID, pv1.Date