【入門編】なぜそのコードは遅いのか?VBAの実行速度を測定・最適化するためのプロファイリング基礎 – Excel VBA解析バイブル

スポンサーリンク

こんにちは!マクロの記録を卒業し、「自分で一からコードを書けるようになりたい!」と一歩を踏み出したあなたへ。

Excel VBAを書いていると、ふとこんな壁にぶつかりませんか?

「あれ……? さっき書いたマクロ、完了するまでにやたら時間がかかるぞ……」

画面がチラつきながら、Excelが固まったように何十秒もフリーズする。終わった頃にはコーヒーがすっかり冷めている。そんな経験はありませんか?

「とりあえず `Application.ScreenUpdating = False`(画面更新の停止)を入れておけば速くなるんでしょ?」
もちろん、それは大正解。でも、それだけでは真の高速化にはたどり着けません。なぜなら、遅さの原因(ボトルネック)を見つけ出さずに闇雲に対策しても、穴の開いたバケツに水を注ぐようなものだからです。

今日は、プロのエンジニアが現場で常に行っている「実行速度の測定(プロファイリング)」と、「根本的なコードの体質改善テクニック」を分かりやすく伝授しますね。
ここをクリアすれば、あなたのVBAは見違えるほど軽快に動くようになりますよ。さあ、一緒に扉を開けましょう!

1. 敵を知る:Timer関数で「どこが遅いか」を暴く

速度を上げるための第一歩は、「どの行が足を引っ張っているのか」を正確に特定することです。ここで登場するのが、VBAの標準関数である `Timer`(タイマー) です。

`Timer` 関数は、午前0時からの経過時間を「秒単位(ミリ秒の精度)」で返してくれます。これを利用して、処理の「前」と「後」の時間を挟み撃ちにし、差分を計算することで、コードの実行にかかった時間を丸裸にできます。

基本の測定パターン

まずは、シンプルなコードで時間を測る感覚を掴んでみましょう。

Sub ProfileSample()
Dim startTime As Double
Dim i As Long

‘ 1. 測定開始の時間を記録
startTime = Timer

‘ — ここから測定したい重い処理 —
For i = 1 to 100000
‘ 何かしらの処理(例:セルに値を書き込む)
‘ Cells(i, 1).Value = i ‘ ※あえてコメントアウトしていますが後述します
Next i
‘ — ここまで —

‘ 2. 終了時の時間から開始時を引いて、経過時間を計算・表示
MsgBox “処理時間: ” & Format(Timer – startTime, “0.00プロファイリング秒”)

End Sub

このように、「疑わしいブロックの前後で `Timer` を挟む」。これがプロファイリングの基本中の基本です。あちこちにこれを仕込むことで、「あ、このループの中身が原因で2秒もかかってるぞ」と犯人を特定できるわけです。

2. なぜそのコードは遅いのか? VBAが遅くなる3大悪

犯人がわかったところで、VBA初心者・中級者がやりがちな「3大・爆遅コーディングパターン」を見ていきましょう。

悪行①:シートと「何往復も」会話している(セルへの直接アクセス)

VBAからExcelのシート(セル)にアクセスする行為は、実はパソコンにとって「ものすごく重い重労働(=オーバーヘッド)」です。

  • ダメな例: ループの中で1回ずつセルを書き換える

For i = 1 to 10000
Cells(i, 1).Value = “テスト” ‘ これを1万回やると、Excel君は1万回シートを見に行く
Next i

これは、わざわざ1個ずつみかんを段ボールから取り出して隣の部屋に運ぶようなもの。疲れますよね。

悪行②:不要なイベントや計算を走らせている

セルの値が変わるたびに、Excelは「他のセルに影響はないか?(自動計算)」「シートの見た目を更新しなきゃ!(画面描画)」「マクロが仕掛けられてないか?(イベント)」と、余計なお世話を次々に実行します。これが速度低下の大きな原因です。

悪行③:Variant型の乱用

データ型を明示せず `Dim x` などと宣言すると、VBAは「Variant(何でも入る万能型)」として扱います。これがメモリ上で余計な計算コストを生む原因になります。

3. 画面更新停止だけじゃない! 劇的スピードアップの3大奥義

では、これらの「遅さ」をどう撃退するのか?
今すぐ使える実践的な高速化テクニックを3つ紹介します。

奥義①:メモリ上で一網打尽!「配列(Array)処理」

先ほどの「セルとの何往復もの会話」を解決するのが配列です。
「シートのデータを一気にVBAのメモリ(変数)に読み込み、メモリ上で高速に料理して、最後に一気にシートへ書き戻す」。これが王道の高速化テクニックです。

Sub FastArraySample()
Dim startTime As Double
startTime = Timer

Dim ws As Worksheet
Set ws = ActiveSheet

‘ 1. セルのデータを一気に「二次元配列」に読み込む(爆速化のキモ!)
‘ A1:A10000 のデータをまるごとメモリに拉致します
Dim dataArr As Variant
dataArr = ws.Range(“A1:A10000”).Value

Dim i As Long
‘ 2. メモリ上(配列内)でデータを書き換える(シートを見に行かないので超速い)
For i = 1 To UBound(dataArr, 1)
dataArr(i, 1) = “更新完了_” & i
Next i

‘ 3. 書き換えた配列を、一気にシートへ吐き出す
ws.Range(“A1:A10000”).Value = dataArr

MsgBox “配列を使った高速処理完了! 経過時間: ” & Format(Timer – startTime, “0.00秒”)
End Sub

このコードを動かすと、セルを1つずつ触っていたコードとは比較にならないほどのスピード(体感で数十倍以上!)で処理が完了することに驚くはずです。

奥義②:Excelの「お節介」を一時的にシャットダウンする

マクロ実行中は、Excelの余計な機能を強制停止させます。これをセットで覚えておきましょう。

Sub ProMacroTemplate()
‘ — 【準備】Excel君にお静かに願う —
With Application
.ScreenUpdating = False // 画面の描き換えを停止(必須)
.Calculation = xlCalculationManual // 自動計算を手動に(数式が多いシートで効果絶大)
.EnableEvents = False // イベント(Worksheet_Changeなど)を無効化
End With

On Error GoTo ErrorHandler ‘ エラー時に設定が戻らなくなるのを防ぐ安全装置

‘ ==========================================
‘ ここにメインの重い処理を書く
‘ ==========================================

ErrorHandler:
‘ — 【後片付け】必ず元に戻す! —
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With

If Err.Number <> 0 Then
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
End If
End Sub

※特に `.Calculation = xlCalculationManual` は、VLOOKUP関数やSUMIF関数が大量にある重いシートで数秒〜数分の短縮を生む強力な設定です。

奥義③:型を制する者はVBAを制する(データ型の明示)

変数を宣言するときは、必ず `Dim i As Long` のように型を指定しましょう。特にループカウンターには `Long` 型(整数型)を使うのが鉄則です(`Integer` よりも `Long` の方が32bit環境の現代のPCでは処理が最適化されて高速に動きます)。

4. まとめ:プログラミングの美しさは「効率」に宿る

「動けばいいや」と書いたコードは、データが増えた途端に使い物にならなくなります。しかし、今日学んだ「Timerによる測定」「配列・環境設定の制御」の視点を持てば、あなたはもう「動くだけのマクロの記録ユーザー」ではありません。

「どうすればパソコンに無駄な苦労をさせずに、最短ルートで仕事を終わらせられるか?」

この視点を持てるようになったあなたなら、どんな巨大なExcelファイルが来ても怖くありません。ぜひ、手元の遅いマクロで試してみてくださいね。驚きのスピードに感動するはずです。

ここをクリアすれば、Excel VBAの基本はバッチリですよ!次のステップへ進んで、さらにスマートな自動化の世界を楽しみましょう!

タイトルとURLをコピーしました