〖ExcelVBA・マクロ〗フリーズしない大量処理の書き方|固まらない・止まらないマクロ設計の基本

フリーズしない大量処理の書き方 ExcelVBA

ExcelVBAで大量のデータを処理すると、次のような状態になりがちです。

  • 処理中にExcelが固まったように見える
  • 「応答なし」と表示される
  • 本当に動いているのか不安になる
  • 強制終了してデータを壊してしまった

しかし実は、VBAがフリーズする原因のほとんどは「書き方」です。
正しい設計にすれば、数万行・数十万行の処理でも固まらずに実行できます。

この記事では、初心者でも実践できる 「フリーズしない大量処理の基本ルール」を、理由つきで解説します。


スポンサーリンク
スポンサーリンク

結論:フリーズしないVBAは「3つの設計」で決まる

大量処理でも固まらないマクロには、共通点があります。

  • ① Excelの画面更新・計算を制御している
  • ② セルを直接いじらず、配列で処理している
  • ③ DoEventsでExcelに処理を返している

この3つを押さえるだけで、体感速度と安定性は劇的に変わります。


原因①:セルを1つずつ直接操作している

フリーズの最大原因はこれです。

For i = 1 To 100000
    Cells(i, 1).Value = Cells(i, 1).Value * 2
Next i

一見普通ですが、
1行ごとにExcel画面・計算・内部処理が走るため、極端に遅くなります。


対策①:配列に読み込んでから一気に書き戻す

大量処理の基本は 「配列処理」 です。

Sub Sample_ArrayProcess()

    Dim v As Variant
    Dim i As Long

    ' 一括で配列に読み込み
    v = Range("A1:A100000").Value

    ' メモリ上で処理
    For i = 1 To UBound(v, 1)
        v(i, 1) = v(i, 1) * 2
    Next i

    ' 一括で書き戻し
    Range("A1:A100000").Value = v

End Sub

これだけで、処理速度は数十倍〜数百倍変わります。


原因②:画面更新・自動計算がONのまま

大量処理中に、Excelは次のことを常に行っています。

  • 画面を更新する
  • 数式を再計算する
  • イベントを発火させる

これらは処理中は不要なので、OFFにします。


対策②:処理前に「高速化3点セット」を入れる

Dim prevCalc As XlCalculation
Dim prevScreen As Boolean
Dim prevEvents As Boolean

' 現在の状態を退避
prevCalc = Application.Calculation
prevScreen = Application.ScreenUpdating
prevEvents = Application.EnableEvents

' 高速化
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False

処理後は、必ず元に戻します。

Application.ScreenUpdating = prevScreen
Application.Calculation = prevCalc
Application.EnableEvents = prevEvents

※戻し忘れると「Excelが壊れた」と勘違いされる原因になります。


原因③:Excelに処理を返していない(DoEventsなし)

VBAは処理中、Excelを占有します。
そのため、長いループでは「応答なし」になりがちです。


対策③:定期的にDoEventsを入れる

For i = 1 To 100000

    ' 処理
    v(i, 1) = v(i, 1) * 2

    ' 1000件ごとにExcelへ制御を返す
    If i Mod 1000 = 0 Then
        DoEvents
    End If

Next i

これで、

  • 画面更新が反映される
  • キャンセルボタンが効く
  • フリーズして見えなくなる問題を防げる

応用①:進捗を表示して「動いている感」を出す

フリーズと誤解されないためには、進捗表示が有効です。

Application.StatusBar = "処理中:" & i & " / " & UBound(v, 1)

処理後は必ず元に戻します。

Application.StatusBar = False

応用②:キャンセル可能な大量処理にする

キャンセルフラグと組み合わせると、実務向けになります。

If gCancel Then
    MsgBox "処理を中断しました。", vbExclamation
    Exit For
End If

gCancel は「キャンセルボタンの記事」で紹介したフラグです。


よくある失敗例

  • 配列を使っていない
  • 高速化設定を戻していない
  • DoEventsを入れすぎて逆に遅くしている
  • 進捗表示がなく、不安にさせている

特に DoEventsの入れすぎ は逆効果なので、 「数百〜数千件に1回」が目安です。


安全な大量処理テンプレ(実務向け)

Option Explicit

Sub SafeLargeProcess()

    Dim prevCalc As XlCalculation
    Dim prevScreen As Boolean
    Dim prevEvents As Boolean
    Dim v As Variant
    Dim i As Long

    On Error GoTo Finally

    ' 状態退避
    prevCalc = Application.Calculation
    prevScreen = Application.ScreenUpdating
    prevEvents = Application.EnableEvents

    ' 高速化
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False

    ' 配列処理
    v = Range("A1:A100000").Value

    For i = 1 To UBound(v, 1)

        v(i, 1) = v(i, 1) * 2

        If i Mod 1000 = 0 Then
            DoEvents
        End If

    Next i

    Range("A1:A100000").Value = v

Finally:
    ' 必ず元に戻す
    Application.ScreenUpdating = prevScreen
    Application.Calculation = prevCalc
    Application.EnableEvents = prevEvents
    Application.StatusBar = False

End Sub

まとめ:大量処理は「設計」で決まる

  • セルを直接触らず、配列で処理する
  • 画面更新・計算・イベントを制御する
  • DoEventsでExcelを固まらせない
  • 進捗表示で安心感を出す

この設計を身につけると、 「VBAが遅い・固まる」問題の9割は解決します。

ぜひ、実務マクロの基本として取り入れてみてください。

スポンサーリンク
スポンサーリンク
ExcelVBA
いがぴをフォローする

コメント

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