4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Excel VBAが30倍速く!? 定番の高速化テクニック5つを試してみた

Last updated at Posted at 2025-07-28

「Excel VBAが遅すぎて、フリーズ寸前…。もう使いたくない!」
そんな経験、ありませんか?

本記事では10万セル規模の大量データ処理を題材に、定番の高速化テクニック5つ実測データ付きで比較します。

なぜVBAは遅くなるのか?

VBAで大量のセルにアクセスする処理を組むと、裏で以下のような余計な処理が走ります。

  • セル描画のたびに画面更新
  • 式変更のたびに再計算が走る
  • Worksheet_Changeなどのイベントが毎回発火する

このような処理が積み重なることで、実行時間が激増してしまいます。

高速にする5つのテクニック

高速化テクニック 効果レベル※ 解説
無駄なSelectをやめる ★★★★☆ 不要な選択操作を排除して処理を簡素化
Application.ScreenUpdating
= False
★★★☆☆ 画面描画を一時停止
Application.Calculation
= xlCalculationManual
★★★☆☆ 再計算を一時停止
配列で一括書き込み ★★★★★ 一括でセルに出力
Withブロックで命令まとめる ★☆☆☆☆ 同じオブジェクトへの命令を省略化

※今回の計測同様の処理に適用した場合の効果レベルです

計測

本記事では、上記のテクニックを個別に実施しその効果を確認していきます。
また最後に全てのテクニックを適用したパターンについても確認します。

計測環境

今回は以下の環境での計測を行います。
やや古い環境ですが、ご参考になれば幸いです。

  • Excel : 2016
  • OS : Windows 11
  • CPU : Intel(R) Core i7-8700K
  • メモリ : 32 GB

実行時間に関する注意点
実行速度はPCスペックや他ソフトの動作状況により変動するため、実行結果の数値はあくまで参考値としてご覧ください。
再現する際は、複数回の平均を推奨します。

① 無駄なSelectをやめる

選択セルを変更すると、Excelは画面を都度更新します。
この更新が多くなると負荷が高くなり、描画処理が遅くなります。

値の出力はSelectを使わなくても実行できるため為、Selectを無くすことで高速化を図ります。

計測処理

クリックでコードを表示
Sub Test_NonSelect()
    Dim startTime As Double, endTime As Double
    Dim i As Long, j As Long

    ' --- 高速化なし(Selectあり) ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Select          ' 出力するセルを選択
            Cells(i, j).Value = i * j   ' 「行数×列数」の値を出力
        Next j
    Next i

    endTime = Timer
    Debug.Print "[Selectあり] 時間: " & Format(endTime - startTime, "0.000") & " 秒"

    ' --- 高速化(Selectなし) ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Value = i * j   ' 「行数×列数」の値を出力
        Next j
    Next i
    
    endTime = Timer
    Debug.Print "[Selectなし] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
End Sub

計測結果

上記の処理を10回実行した結果を以下の表にまとめました。
Selectを行わないだけで約28倍の速度で処理を行えています。

回数 Selectあり(秒) Selectなし(秒) 効果(倍率)
1 98.002 3.445 28.45
2 103.252 3.463 29.82
3 104.541 3.621 28.87
4 104.451 3.539 29.51
5 104.807 3.568 29.37
6 95.207 3.477 27.38
7 101.193 3.500 28.91
8 95.480 3.516 27.16
9 97.410 3.566 27.32
10 96.199 3.451 27.88
平均 100.0542 3.5146 28.47

② 画面更新の停止:ScreenUpdating

値を入れたりするたびに、Excelは画面を都度更新します。
この更新が多くなると負荷が高くなり描画処理が遅くなります。

処理の前にApplication.ScreenUpdating = Falseとすることで、描画処理を一時停止させ高速化を図ります。

計測処理

クリックでコードを表示
Sub Test_ScreenUpdating()
    Dim startTime As Double, endTime As Double
    Dim i As Long, j As Long

    ' --- 高速化なし(画面更新あり) ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Select          ' 出力するセルを選択
            Cells(i, j).Value = i * j   ' 「行数*列数」の値を出力
        Next j
    Next i

    endTime = Timer
    Debug.Print "[画面更新あり] 時間: " & Format(endTime - startTime, "0.000") & " 秒"

    ' --- 高速化(画面更新なし) ---
    Application.ScreenUpdating = False ' 描画処理を一時停止

    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Select          ' 出力するセルを選択
            Cells(i, j).Value = i * j   ' 「行数*列数」の値を出力
        Next j
    Next i

    Application.ScreenUpdating = True ' ← 元に戻すのを忘れない!
    
    endTime = Timer
    Debug.Print "[画面更新なし] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
End Sub

計測結果

上記の処理を10回実行した結果を以下の表にまとめました。
描画処理を一時停止することで約12倍の速度で処理を行えています。

回数 画面更新あり(秒) 画面更新なし(秒) 効果(倍率)
1 96.572 7.799 12.38
2 98.453 7.971 12.35
3 97.314 7.949 12.24
4 102.188 7.795 13.11
5 96.209 7.900 12.18
6 96.984 8.006 12.11
7 107.492 8.189 13.13
8 97.143 7.840 12.39
9 96.730 7.889 12.26
10 97.324 7.918 12.29
平均 98.6409 7.9256 12.44

③ 自動計算の停止:Calculation

セルに数式を入れると、Excelは自動的に再計算します。
この再計算が何千回も繰り返されると大きな負担になります。

Application.Calculation = xlCalculationManualで再計算を一時的に停止して高速化を図ります。
なお、数式の単純な計算式ほどこのテクニックの効果は薄くなります。

計測処理

クリックでコードを表示
Sub Test_Calculation()
    Dim startTime As Double, endTime As Double
    Dim i As Long, j As Long

    ' --- 高速化なし(自動計算あり) ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Formula = "=" & i & "*" & j & "*2"  ' 「行数*列数*2」の式を出力
        Next j
    Next i

    endTime = Timer
    Debug.Print "[自動計算あり] 時間: " & Format(endTime - startTime, "0.000") & " 秒"

    ' --- 高速化(自動計算なし) ---
    Application.Calculation = xlCalculationManual ' 自動計算の停止

    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Formula = "=" & i & "*" & j & "*2"  ' 「行数*列数*2」の式を出力
        Next j
    Next i

    Application.Calculation = xlCalculationAutomatic ' ← 元に戻すのを忘れない!
    
    endTime = Timer
    Debug.Print "[自動計算なし] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
End Sub

計測結果

上記の処理を10回実行した結果を以下の表にまとめました。
自動計算を一時停止することで約10倍の速度で処理を行えています。

回数 自動計算あり(秒) 自動計算なし(秒) 効果(倍率)
1 63.104 5.510 11.45
2 55.648 5.600 9.94
3 61.150 5.494 11.13
4 55.098 5.555 9.92
5 59.361 6.416 9.25
6 59.111 5.570 10.61
7 54.748 5.527 9.91
8 58.980 5.525 10.68
9 54.201 5.697 9.51
10 55.211 5.918 9.33
平均 57.6612 5.6812 10.17

④ 配列で一括書き込み

大量のデータを各セルに随時出力していくと、ExcelとVBA間のやりとりが頻繁になり非常に遅くなります。

一度配列に値をまとめてから、一括で書き込むことで劇的に速くなります。

計測処理

クリックでコードを表示
Sub Test_UseArray()
    Dim startTime As Double, endTime As Double
    Dim i As Long, j As Long

    ' --- 高速化なし(遂次出力) ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Value = i * j   ' 随時「行数*列数」の値を出力
        Next j
    Next i

    endTime = Timer
    Debug.Print "[遂次出力] 時間: " & Format(endTime - startTime, "0.000") & " 秒"

    ' --- 高速化(配列一括書き込み) ---
    Cells.Clear
    startTime = Timer

    ' データ準備   
    Dim data(1 To 10000, 1 To 10) As Variant
    For i = 1 To 10000
        For j = 1 To 10
            data(i, j) = i * j ' 配列に出力内容(「行数*列数」の値)を格納
        Next j
    Next i

    Range("A1").Resize(10000, 10).Value = data  ' 配列を使って一括出力

    endTime = Timer
    Debug.Print "[配列一括] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
End Sub

計測結果

上記の処理を10回実行した結果を以下の表にまとめました。
配列で一括出力することで約35倍の速度で処理を行えています。

回数 遂次出力(秒) 配列一括(秒) 効果(倍率)
1 3.730 0.094 39.68
2 3.684 0.102 36.12
3 3.734 0.109 34.26
4 3.703 0.109 33.97
5 3.762 0.113 33.29
6 3.719 0.094 39.56
7 3.652 0.113 32.32
8 3.684 0.109 33.80
9 4.223 0.113 37.37
10 3.699 0.105 35.23
平均 3.759 0.1061 35.56

⑤ Withブロックで命令まとめる

同一のセルに値の出力や書式の設定等を行う場合、毎回オブジェクトを指定すると何度も同じオブジェクトにアクセスすることになり処理が遅くなります。

With ~ End Withを使って1回だけオブジェクトの取得し、
複数プロパティをまとめて変更することで命令の重複を省略しつつ高速化を図ります。

計測処理

クリックでコードを表示
Sub Test_UseWith()
    Dim startTime As Double, endTime As Double
    Dim i As Long, j As Long
    Dim cell As Range

    ' --- 高速化なし(Withなし) ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            ' 毎回対象のオブジェクト達にアクセスして更新
            Cells(i, j).Value = i * j
            Cells(i, j).Interior.Color = RGB(255, 255, 153)
            Cells(i, j).Font.Bold = True
            Cells(i, j).Font.Color = vbRed
        Next j
    Next i

    endTime = Timer
    Debug.Print "[Withなし] 時間: " & Format(endTime - startTime, "0.000") & " 秒"

    ' --- 高速化(Withあり) ---
    Cells.Clear
    startTime = Timer
    For i = 1 To 10000
        For j = 1 To 10
            Set cell = Cells(i, j)
            ' Withを使用して一括更新
            With cell
                .Value = i * j
                .Interior.Color = RGB(255, 255, 153)
                With .Font
                    .Bold = True
                    .Color = vbRed
                End With
            End With
        Next j
    Next i
    endTime = Timer
    Debug.Print "[Withあり] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
End Sub

計測結果

上記の処理を10回実行した結果を以下の表にまとめました。
Withでの効果は1.06倍となりました。

効果は限定的ですが、記述の簡潔さ・可読性向上にも寄与します。

回数 Withなし(秒) Withあり(秒) 効果(倍率)
1 19.090 17.074 1.12
2 17.074 19.559 0.87
3 19.715 19.109 1.03
4 19.746 18.656 1.06
5 19.895 18.617 1.07
6 21.180 19.672 1.08
7 19.855 18.477 1.07
8 19.883 18.535 1.07
9 20.039 18.582 1.08
10 19.777 18.520 1.07
平均 19.426 18.274 1.06

5つすべてを適用してみた

最後に、今回紹介した5つのテクニックを全てを適用した場合の効果を確認します。

クリックでコードを表示
Sub Test_AllTechniquesCombined()
    Dim startTime As Double, endTime As Double
    Dim i As Long, j As Long

    ' --- 高速化なし ---
    Cells.Clear
    startTime = Timer

    For i = 1 To 10000
        For j = 1 To 10
            Cells(i, j).Select
            Cells(i, j).Formula = "=" & i & "*" & j & "*2"
            Cells(i, j).Interior.Color = RGB(255, 255, 153)
            Cells(i, j).Font.Bold = True
            Cells(i, j).Font.Color = vbRed
        Next j
    Next i
    
    endTime = Timer
    Debug.Print "[高速化なし] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
    
    ' --- 高速化あり(全テクニック使用) ---
    Dim data(1 To 10000, 1 To 10) As Variant
    Dim cell As Range

    Application.ScreenUpdating = False  ' 描画処理を一時停止
    Application.Calculation = xlCalculationManual   ' 自動計算を一時停止

    Cells.Clear
    startTime = Timer
    
    ' データ準備
    For i = 1 To 10000
        For j = 1 To 10
            data(i, j) = "=" & i & "*" & j & "*2"
        Next j
    Next i

    ' Selectなし、配列一括書き込み
    Range("A1").Resize(10000, 10).Formula = data

    ' 一括書き込み後にWithで書式設定
    For i = 1 To 10000
        For j = 1 To 10
            Set cell = Cells(i, j)
            With cell
                .Interior.Color = RGB(255, 255, 153)
                With .Font
                    .Bold = True
                    .Color = vbRed
                End With
            End With
        Next j
    Next i

    endTime = Timer

    Application.Calculation = xlCalculationAutomatic    ' 自動計算を戻す
    Application.ScreenUpdating = True     ' 描画処理を戻す

    Debug.Print "[全テクニック適用] 時間: " & Format(endTime - startTime, "0.000") & " 秒"
End Sub

計測結果

上記の処理を10回実行した結果を以下の表にまとめました。
今回紹介したテクニックをすべて使用した場合のの効果は約34.12倍となりました。

回数 高速化なし(秒) 高速化あり(秒) 効果(倍率)
1 363.211 9.914 36.64
2 331.008 9.883 33.49
3 331.250 9.805 33.78
4 322.414 9.680 33.31
5 313.719 9.492 33.05
6 329.688 9.570 34.45
7 340.563 9.516 35.79
8 324.000 9.484 34.16
9 319.750 9.617 33.25
10 321.656 9.664 33.28
平均 329.7259 9.6625 34.12

結果まとめ

高速化テクニック Before After 効果 効果レベル(速度)
無駄なselectをやめる 100.05 秒 3.51 秒 約28.5倍 ★★★★☆
画面更新の停止
(ScreenUpdating)
98.64 秒 7.93 秒 約12.4倍 ★★★☆☆
自動計算の停止
(Calculation)
57.66 秒 5.68 秒 約10.2倍 ★★★☆☆
配列で一括書き込み 3.76 秒 0.11 秒 約35.6倍 ★★★★★
Withブロックで命令まとめる 19.43 秒 18.52 秒 約1.1倍 ★☆☆☆☆
5つ全て 329.73 秒 9.66 秒 約34.1倍 ★★★★★

総まとめ

  • VBAの遅さの原因は、画面更新や都度アクセスなどの余計な処理にあり。
  • それらを止めたりまとめたりすることで、処理速度は10〜30倍以上に向上することも。
  • 特に効果が大きかったのは、配列による一括書き込みSelectの排除
  • Withのような小技も、繰り返し処理では意外と効く場面がある。
  • 処理内容によって効くテクニックは異なるため、実務に合わせて使い分けるのが重要

その他の高速化テクニック

本記事で紹介した5つのテクニックは、VBA高速化の定番かつ汎用的な方法です。

今後以下のような追加テクニックも別記事で紹介予定です。

  • イベントの一時無効化Worksheet_Changeイベントなどのトリガーを停止
  • DoEventsの効果と注意点
  • VBEの最適化設定オプション設定、コードモジュール整理など
  • オブジェクト変数の使いまわし、ネストの簡素化

気になる内容があればフォロー・ストックしていただけると嬉しいです!

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?