各ユニットに割り当てられた特定の「引退率」のセットを前提として、長年にわたってさまざまな「環境」を持つさまざまな国でさまざまな配置/出荷のユニットの設置ベースを計算する必要があります。配置、曲線の定義、および曲線の割り当ては、さまざまなデータベーステーブルに保存されます(以下のDDLおよびサンプルデータとともに、SQLFiddle.comにもあります)。設置ベースの計算式は次のとおりです。
ここで、1990年は配置データを取得した最初の年です。
問題:
ユニット/国/環境/年の配置の組み合わせが300万から1600万行のデータセットを使用してこれらの計算を行うと、目標の負荷/計算時間である30秒から1分よりもはるかに時間がかかります。
SQLServerのアプローチ
PIVOT
毎年独自の列になるように編集すると、100,000から40万の生データ(プレースメント+レート)の返される行が取得されます。これには約8〜15秒かかります。ただし、以下に示すようにSQLステートメントを使用してこれを手動で計算する場合は、少なくとも10分かかります。
また、プレースメントまたはレートが変更されるたびにインストールベースを更新するSQLトリガーソリューションを試しましたが、バッチ更新ではデータベースの更新が不当に遅くなり、信頼性も低くなりました。これが本当に最良の選択肢であるならば、これはさらに調査する価値があると思います。
Excel-VSTOアプローチ(これまでのところ、最速のアプローチ):
このデータは最終的にC#VSTOを利用したExcelワークブックになり、一連のデータを介して計算されますが、VLOOKUPs
6年間で150,000プレースメントをVLOOKUPs
セルあたり約20(約2,000万VLOOKUPs
)ロードすると、Excelがクラッシュします。小さなバッチで実行され、VLOOKUPs
数式が値に変換される場合、クラッシュは発生しませんが、計算には1分以上かかります。
質問:
これまでよりも効率的に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'