大規模Project VBAの深淵:ベースライン比較を「秒速」で完遂するメモリ最適化アーキテクチャ
数万行のタスクを抱えるProjectファイルを開き、標準の「ベースライン比較」機能でPCをフリーズさせた経験はないだろうか?
多くのエンジニアが陥る罠は、VBAの`Project.Tasks`オブジェクトを愚直にループさせ、プロパティを逐一読み込むことだ。あれはメモリ管理の観点から見れば、自ら火の中に飛び込む行為に等しい。COMインターフェースを介したアクセスは非常にコストが高い。大規模データにおいて、我々が扱うべきは「オブジェクト」ではなく「生存可能な最小単位のデータ」である。
今回は、数万タスクの差分抽出を秒単位で完了させる、バイナリ比較思想に基づいたメモリ最適化手法を伝授する。
—
1. なぜ「オブジェクト」を直接触ってはいけないのか
VBAで`Task.Start`や`Task.Finish`をループ内で呼び出すと、その都度COM経由でメモリのマーシャリングが発生する。数万行あれば、このオーバーヘッドだけで数分を浪費する。
真のアーキテクトはこう設計する:
1. データの一括キャッシュ化: `Task`オブジェクトの全プロパティを、一度の操作で配列(Variant型)に流し込む。
2. ハッシュ値による高速フィルタリング: タスクの固有IDと重要な属性(開始日、終了日、コスト)を連結し、文字列ハッシュ(あるいは単純なチェックサム)を生成する。
3. バイナリ的比較: 実データの比較は、ハッシュが一致しない「差異の可能性がある行」に対してのみ実行する。
—
2. 実装:高速差分抽出エンジン
以下のコードは、Projectのタスク情報をメモリ上にフラット展開し、高速に比較するための基盤となる。
Option Explicit
‘ 大規模データ処理のため、Taskのプロパティを構造体または配列として保持する
Private Type TaskSnapshot
ID As Long
UniqueID As Long
Hash As String
End Type
‘ 核心:Projectのタスクを高速に取得し、差分を抽出する
Public Sub CompareBaselineHighSpeed(ByRef proj As Project)
Dim tsk As Task
Dim taskCount As Long: taskCount = proj.Tasks.Count
Dim snapshots() As TaskSnapshot
ReDim snapshots(1 To taskCount)
Dim i As Long: i = 1
‘ 1. メモリへの全ロード (高速化の肝)
‘ 実際にはTaskの全プロパティを読み込むのではなく、比較に必要な情報のみを抽出
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
snapshots(i).UniqueID = tsk.UniqueID
‘ 開始日と終了日を連結してハッシュ化 (簡易的なバイナリ的比較)
snapshots(i).Hash = GenerateHash(tsk.Start, tsk.Finish, tsk.Cost)
i = i + 1
End If
Next tsk
‘ 2. ここで別バージョンのプロジェクトと比較を行う
‘ Dictionaryオブジェクト等を用い、UniqueIDをキーにHashを突き合わせる
‘ 一致しないものだけが「差分」として特定される
Debug.Print “全タスクの解析完了。差分チェックへ移行…”
End Sub
‘ ハッシュ生成関数
Private Function GenerateHash(s As Date, f As Date, c As Double) As String
‘ 比較コストを最小化するため、主要プロパティを文字列結合して一意な値にする
GenerateHash = Format(s, “yyyyMMdd”) & “_” & Format(f, “yyyyMMdd”) & “_” & CStr(c)
End Function
—
3. 運用上の絶対的鉄則:メモリと保守性
この設計を採用するにあたり、以下の3点を必ず遵守せよ。
- Dictionaryの活用: `Scripting.Dictionary`を用いて、`UniqueID`をキーにしたルックアップテーブルを作成すること。これにより、比較アルゴリズムの計算量は `O(N^2)` から `O(N)` へ劇的に改善される。
- Late Bindingの回避: 参照設定(Microsoft Project Object Library)を確実に行い、Early Bindingで型を明示せよ。Variant型での乱用はメモリリークの温床であり、大規模プロジェクトでは致命傷になる。
- ファイルI/Oの最小化: レポートを出力する際、セルに直接書き込むのは厳禁だ。二次元配列に差分結果を格納し、`Range.Value = Array` で一括転送せよ。
4. 結論:なぜこれが「伝説」なのか
多くのエンジニアは「VBAは遅い」と口を揃える。しかし、それはVBAが遅いのではない。「アプリケーションのオブジェクトモデル」を「メモリ上のデータ構造」と混同しているあなたの設計が遅いだけだ。
プロジェクトの規模が大きくなればなるほど、オブジェクト指向の過剰な適用は足枷となる。必要なデータだけを抽出し、メモリ上でバイナリに近い感覚で処理する。この感覚こそが、数万行のプロジェクトを数秒で掌握する唯一の解である。
さあ、あなたのプロジェクトファイルを、単なる「管理ツール」から「高速演算エンジン」へと昇華させたまえ。
