考虑到分配给每个单元的一组特定“退休率”,我需要计算多年来在不同国家具有不同“环境”的不同放置/出货量的单元的安装基数。放置、曲线定义和曲线分配存储在不同的数据库表中(下面有 DDL 和示例数据,也在SQLFiddle.com上)。安装基数的计算公式如下:
其中 1990 年是我们有安置数据的第一年。
问题:
使用包含 3 到 1600 万行单位/国家/环境/年份放置组合的数据集进行这些计算所花费的时间比 30 秒到 1 分钟的目标加载/计算时间要长得多。
Sql Server 方法
当PIVOT
ed 使每年成为自己的列时,我会得到 100,000 到 400,000 行返回的原始数据(展示位置 + 费率),这大约需要 8-15 秒。但是,如果我要通过如下所示的 SQL 语句手动计算,则至少需要10 分钟。
我们还尝试了一种 SQL 触发器解决方案,该解决方案在每次修改位置或费率时更新安装基础,但这会使数据库更新在批量更新时异常缓慢,而且也不可靠。如果这真的是最好的选择,我想这可能值得更多的调查。
Excel-VSTO 方法(到目前为止,最快的方法):
这些数据最终以 C# VSTO 驱动的 Excel 工作簿结束,其中数据是通过VLOOKUPs
一系列. 当以较小的批次完成并将公式转换为值时,它不会崩溃,但计算时间仍然超过一分钟。VLOOKUPs
VLOOKUPs
VLOOKUPs
问题:
是否有一些数学或编程构造可以帮助我通过 C# 或 SQL 比我一直在做的更有效地计算这些数据?蛮力迭代也太慢了,所以这也不是一个选择。
DECLARE @Placements TABLE
(
UnitId int not null,
Environment varchar(50) not null,
Country varchar(100) not null,
YearColumn smallint not null,
Placement decimal(18,2) not null,
PRIMARY KEY (UnitId, Environment, Country, YearColumn)
)
DECLARE @CurveAssignments TABLE
(
UnitId int not null,
Environment varchar(50) not null,
Country varchar(100) not null,
YearColumn smallint not null,
RateId int not null,
PRIMARY KEY (UnitId, Environment, Country, YearColumn)
)
DECLARE @CurveDefinitions TABLE
(
RateId int not null,
YearOffset int not null,
Rate decimal(18,2) not null,
PRIMARY KEY (RateId, YearOffset)
)
INSERT INTO
@Placements
(
UnitId,
Country,
YearColumn,
Environment,
Placement
)
VALUES
(
1,
'United States',
1991,
'Windows',
100
),
(
1,
'United States',
1990,
'Windows',
100
)
INSERT INTO
@CurveAssignments
(
UnitId,
Country,
YearColumn,
Environment,
RateId
)
VALUES
(
1,
'United States',
1991,
'Windows',
1
)
INSERT INTO
@CurveDefinitions
(
RateId,
YearOffset,
Rate
)
VALUES
(
1,
0,
1
),
(
1,
1,
0.5
)
SELECT
P.UnitId,
P.Country,
P.YearColumn,
P.Placement *
(
SELECT
Rate
FROM
@CurveDefinitions CD
INNER JOIN @CurveAssignments CA ON
CD.RateId = CA.RateId
WHERE
CA.UnitId = P.UnitId
AND CA.Environment = P.Environment
AND CA.Country = P.Country
AND CA.YearColumn = P.YearColumn - 0
AND CD.YearOffset = 0
)
+
(
SELECT
Placement
FROM
@Placements PP
WHERE
PP.UnitId = P.UnitId
AND PP.Environment = P.Environment
AND PP.Country = P.Country
AND PP.YearColumn = P.YearColumn - 1
)
*
(
SELECT
Rate
FROM
@CurveDefinitions CD
INNER JOIN @CurveAssignments CA ON
CD.RateId = CA.RateId
WHERE
CA.UnitId = P.UnitId
AND CA.Environment = P.Environment
AND CA.Country = P.Country
AND CA.YearColumn = P.YearColumn
AND CD.YearOffset = 1
) [Installed Base - 1993]
FROM
@Placements P
WHERE
P.UnitId = 1
AND P.Country = 'United States'
AND P.YearColumn = 1991
AND P.Environment = 'Windows'