貴方のVBAコードはなぜ遅いのか?「セル直接操作」という名の罪と、メモリ配列による100倍速の極意
業務自動化エンジニアとして数多のプロジェクトを渡り歩いてきたが、未だに「セルを1つずつ読み書きする」コードに出くわす。シート上のセルをループで走査するその処理は、まるで砂漠でスプーン一杯ずつ水を運ぶようなものだ。
Excelの処理速度を殺している最大の犯人は、VBAとワークシート間の通信回数にある。セルにアクセスするたび、Excelは計算エンジンの再評価や再描画といった「重い処理」を裏で行っている。
この記事では、セルを一括でメモリ(配列)に引き上げ、計算を完結させてから一気に掃き出す「配列処理」の極意を伝授する。
—
1. なぜ「セル直接操作」は滅びるべきなのか
以下のコードを見てほしい。これが最も忌むべき「悪しき作法」だ。
‘ 【アンチパターン】絶対にやってはいけない例
For i = 1 To 10000
Cells(i, 1).Value = Cells(i, 1).Value 1.08
Next i
このコードは、1万回の「VBAからシートへの書き込み」が発生する。ネットワーク越しのDB操作ではないのだから、1万回のオーバーヘッドは致命的だ。これでは数秒〜数十秒かかる。
正解は、「メモリ上で完結させること」だ。
—
2. 配列処理の黄金律:Read -> Process -> Write
配列を用いた処理は、以下の3ステップで完結する。
1. Read: `Range.Value` を代入して、メモリ上にVariant配列を作る。
2. Process: メモリ上の配列に対して計算を行う。
3. Write: `Range.Value` に配列を一括代入してシートに書き戻す。
実践:プロダクションレベルのコード例
以下は、保守性を担保しつつ、高速化を追求した実務用テンプレートだ。
Public Sub ProcessDataFast()
Dim ws As Worksheet
Dim rngData As Range
Dim vData As Variant
Dim i As Long
Set ws = ThisWorkbook.Sheets(“Sheet1”)
‘ 1. データ範囲を特定(可変範囲に追従させる)
Set rngData = ws.Range(“A1”).CurrentRegion
‘ 2. メモリへの一括転送(これが高速化の鍵)
vData = rngData.Value
‘ 3. メモリ上での演算(ここが0.01秒で終わる)
‘ ※配列は1ベース(1から始まる)であることに注意
For i = 2 To UBound(vData, 1) ‘ ヘッダーを飛ばして2行目から
‘ 例:1列目の値に消費税を掛けて2列目に格納
vData(i, 2) = vData(i, 1) 1.08
Next i
‘ 4. 一括書き戻し(シートへのアクセスはたった1回)
rngData.Value = vData
MsgBox “処理完了。セルアクセスは最小限に抑えられました。”
End Sub
—
3. 現場で「バグらせない」ための3つの鉄則
配列操作を導入すると、初心者は決まって「配列の次元」や「インデックス」で躓く。これを防ぐための守りだ。
① `Option Base 1` に頼るな
`Option Base 1` を宣言せずとも、`Range.Value` で取得した配列は必ず `1` から始まる。これに甘えず、`LBound(vData, 1)` を使う習慣をつけろ。将来的なデータ構造の変更に強いコードになる。
② `Variant` を使いこなせ
`Dim vData() As String` のように型を固定すると、`Range.Value` からの転送でエラーになることがある。`Value` プロパティは多様なデータ型を内包するため、受け皿は必ず `Variant` 型の動的配列にすること。
③ 範囲外参照を徹底排除せよ
`UBound(vData, 1)` で配列の行数上限を取得できる。ループの終了条件をこれに縛ることで、「データが増えたらエラーになる」という脆弱なコードから脱却できる。
—
4. 最後に:なぜ「エンジニア」であるべきか
Excelの自動化は、単なる事務作業の効率化ではない。「計算リソースの最適化」というエンジニアリングの思考そのものだ。
セルを一つずつ叩くコードを書くのは、PCの性能を捨てているのと同じことだ。配列を制する者はVBAを制する。今日から、「セルに触れる回数」を常にカウントする意識を持て。それが、貴方が現場で「ただの事務担当」から「信頼されるエンジニア」へと進化する第一歩だ。
何か技術的に迷うことがあれば、コードを磨け。磨き上げたコードは、決して貴方を裏切らない。
