Excel VBAでループが遅い原因と高速化のコツ!DoEventsやWith構文を解説
生徒
「先生、大量のデータをループ処理で書き換えるマクロを作ったのですが、動かしている間Excelが固まってしまって、すごく時間がかかるんです…。」
先生
「それは『VBAあるある』ですね。実は、書き方を少し工夫するだけで、処理速度を何十倍も速くすることができるんですよ。」
生徒
「何十倍もですか!?パソコンが壊れかけているのかと思っていました。」
先生
「大丈夫、壊れていませんよ。Excelが一生懸命描画しようとするのを止めたり、無駄な動きを減らしたりするテクニックを教えますね!」
1. なぜVBAのループ処理は遅くなるのか?
Excel VBA(エクセル・ブイビーエー)で繰り返し処理(ループ)を行う際、初心者の方が書いたコードが遅くなる最大の原因は、「Excelの画面描画」と「無駄なアクセス」にあります。
プログラムが1行書き換えるたびに、Excelは「画面を新しく書き直さなきゃ!」と頑張ってしまいます。人間には見えないほど一瞬の動作ですが、これが数千回、数万回と重なると、パソコンに大きな負担がかかり、結果としてマクロが遅くなってしまうのです。
また、セルの情報を読み書きするために何度もエクセルのシートにアクセスすることも時間がかかる原因です。これを解決するための「高速化のコツ」を順番に見ていきましょう。
2. 劇的に速くなる!画面更新の停止(ScreenUpdating)
最も効果が高く、かつ簡単な方法が「画面更新の停止」です。マクロが動いている間、Excelが画面を書き換えるのを一時的に禁止します。
例えるなら、部屋の模様替えをするときに、家具を一つ動かすたびに「どうかな?」と確認するのではなく、全部動かし終わるまでカーテンを閉めておき、最後にパッと開けるようなイメージです。
Sub FastLoopExample()
' 画面更新を停止して高速化!
Application.ScreenUpdating = False
Dim i As Long
For i = 1 To 5000
Cells(i, 1).Value = "テスト中"
Next i
' 最後に必ず元の状態(True)に戻す
Application.ScreenUpdating = True
MsgBox "処理が完了しました。"
End Sub
この Application.ScreenUpdating = False をコードの最初に入れるだけで、体感速度が数倍から数十倍に跳ね上がります。マクロ作成の必須テクニックです。
3. 無駄な再計算を止める(Calculation)
エクセルのシートにたくさんの数式が入っている場合、VBAで一つのセルを書き換えるたびに、すべての数式が「再計算」されます。これもループが遅い大きな原因です。これを「手動計算」に切り替えることで高速化できます。
Sub StopCalculation()
' 計算方法を手動(Manual)に切り替え
Application.Calculation = xlCalculationManual
Dim i As Long
For i = 1 To 1000
Cells(i, 2).Value = i * 1.1
Next i
' 最後に自動計算に戻して、最新の状態にする
Application.Calculation = xlCalculationAutomatic
End Sub
これを忘れると、計算結果が古いままになってしまうので、必ず最後に xlCalculationAutomatic に戻しましょう。
4. With構文で「無駄な名前呼び」を省略する
With(ウィズ)構文を使うと、コードがスッキリするだけでなく、処理もわずかに速くなります。同じ対象(例えば特定のシートやセル)に対して何度も命令を送るとき、その名前を何度も呼ぶ必要がなくなるからです。
例えば、「Sheet1のセルに色を塗って、文字を太くして、値を書き込む」という場合、毎回 Sheets("Sheet1") と書くのは、パソコンにとっても「そのシートはどこだっけ?」と探す手間になります。
Sub WithExample()
' Sheet1に対してまとめて命令を出す
With Sheets("Sheet1").Range("A1")
.Value = "完了"
.Font.Bold = True
.Interior.Color = vbYellow
End With
End Sub
ドット(.)から始まる命令が、With の後ろに書いた対象にかかります。読みやすさも向上するので積極的に使いましょう。
5. 固まるのを防ぐ「DoEvents」の正しい使い方
長時間かかるループを回していると、パソコンが「応答なし」と表示されて固まってしまうことがあります。このとき、パソコンに「ちょっとだけ休憩して、他の作業(マウス操作など)を受け付けていいよ」と許可を与えるのが DoEvents(ドゥ・イベンツ) です。
※注意:DoEventsを入れると処理速度自体は少し遅くなります。しかし、「今どれくらい進んでいるか」を確認したり、途中で停止させたりするために役立ちます。
Sub DoEventsExample()
Dim i As Long
For i = 1 To 10000
Cells(i, 3).Value = "データ入力中"
' 500回に1回、OSに制御を戻す(固まるのを防ぐ)
If i Mod 500 = 0 Then
DoEvents
End If
Next i
End Sub
毎回 DoEvents を呼び出すと遅くなりすぎるため、上記のサンプルのように「500回に1回」など、間隔を空けて実行するのがプロのコツです。
6. オブジェクト変数を使ってアクセスを速める
何度も同じシートや範囲(レンジ)を指定する場合、その対象を変数に入れておく「オブジェクト変数」の活用も効果的です。特に、別のブックやシートを横断して処理する際に威力を発揮します。
Sub ObjectVariableSpeed()
' シートという「物」を変数にセットする
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim i As Long
' 毎回長い名前を書かなくて済むので速い!
For i = 1 To 1000
ws.Cells(i, 4).Value = i
Next i
End Sub
パソコンの内部では、「どのシートか探す」という工程が1回で済むようになるため、非常に効率的になります。
7. セルに直接アクセスする回数を減らす考え方
究極の高速化は、「セルを1回ずつ触らない」ことです。例えば、1万個のセルに値を書き込むとき、1万回 Cells(i, 1).Value = ... と命令するよりも、いったん「配列(はいれつ)」というパソコンのメモリ上のリストにデータを溜め込み、最後に一気にシートへ貼り付ける方が圧倒的に速いです。
これは少し応用的な内容になりますが、「ループの中でシートをいじるのは最小限にする」という意識を持つだけで、マクロの設計が大きく変わります。まずは画面更新の停止から始め、慣れてきたらデータの扱い方を工夫してみましょう。
8. 高速化コードを書く際のテンプレート
これまでに紹介した高速化テクニックを組み合わせた、最も一般的で使いやすい「マクロの型」を紹介します。新しいマクロを作るときは、この形をベースにすると失敗が少なくなります。
Sub SpeedTemplate()
' --- 1. 高速化の開始設定 ---
With Application
.ScreenUpdating = False ' 画面更新停止
.Calculation = xlCalculationManual ' 手動計算
.EnableEvents = False ' イベント停止(応用)
End With
' --- 2. メインのループ処理 ---
' ここにあなたのループコードを書く
' --- 3. 設定を必ず元に戻す ---
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With
MsgBox "すべての処理が終わりました!"
End Sub
このように、最初に止めて、最後に必ず戻すという流れをセットにすることで、安全で爆速なExcel VBAプログラムを作成することができます。これだけで、あなたの業務効率は劇的に向上するはずです!