この記事でわかること
VBAの処理が遅くて困っていないだろうか。1万行のデータ処理に何分もかかる、実行中にExcelが固まる――そんな経験があるなら、この記事が役に立つ。
この記事では、VBAの処理速度を劇的に改善する 3つのテクニック を優先度順に解説する。
- ScreenUpdating=False(1行追加で2.5倍速)
- 配列で一括読み書き(25倍速、最も効果が大きい)
- 全テクニック併用テンプレート(40倍速、コピペですぐ使える)
すべてコピペで動くコード付き。既存のマクロにも簡単に組み込める。
—
どんな場面で使う?
- 1万行以上のデータ処理マクロが何分もかかって業務に支障がある
- セルを1つずつ操作するマクロでExcelが「応答なし」になる
- 既存の遅いマクロを書き換えずに高速化したい
- 大量データの集計・転記をVBAで処理しているが体感速度を改善したい
—
結論:配列を使えば10倍速くなる
先に結論を見せる。1万行×4列のデータを処理した場合のベンチマーク比較がこちら。
| 方法 | 1万行の処理時間 | 速度 |
|---|---|---|
| セル直接操作 | 約8秒 | ×1 |
| ScreenUpdating=False | 約3秒 | ×2.5 |
| 配列で一括読み書き | 約0.3秒 | ×25 |
| 全テクニック併用 | 約0.2秒 | ×40 |
※ 環境(PC性能・Excel版・ブック内の数式量)により数値は変動する。相対的な速度比は概ね同程度。
セル直接操作で8秒かかっていた処理が、配列を使えば0.3秒。全テクニックを併用すれば0.2秒で終わる。配列が最も効果が大きく、ScreenUpdating=FalseやCalculation=xlManualは補助的な役割。ただし数式が多いブックでは Calculation=xlManual の効果が顕著になる。
筆者の実体験: 以前、5万行の売上データを集計するマクロを作ったとき、セル直接操作で30分以上かかっていた。配列に書き換えたら3分で終わるようになった。コードの変更量は20行程度。それだけで27分の短縮になった。
—
なぜVBAの処理が遅くなるのか
VBAが遅くなる原因は主に3つある。
原因1:セルアクセスのオーバーヘッド
VBAからセルに1つずつアクセスするたびに、VBAとExcelの間でデータの変換処理が発生する。1万行×4列のデータなら、4万回のセルアクセスが発生する。
' これが遅い(4万回のセルアクセス)
For i = 2 To 10001
Cells(i, 4) = Cells(i, 1) * Cells(i, 2)
Next i
原因2:画面の再描画
セルの値が変わるたびに、Excelは画面を再描画する。1万回の書き込みがあれば、1万回の画面更新が発生する。
原因3:数式の再計算
シート内に数式があると、セルに値を書き込むたびに数式が再計算される。数式が多いブックほど影響が大きい。
—
テクニック1:Application.ScreenUpdating = False(最も簡単)
最も手軽な高速化テクニック。たった1行追加するだけで、処理速度が約2.5倍になる。
Sub 高速化_画面更新停止()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' ここに処理を書く
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
各設定の意味:
| 設定 | 効果 |
|---|---|
ScreenUpdating = False |
画面の再描画を停止。処理中に画面がチラつかなくなる |
Calculation = xlCalculationManual |
数式の自動再計算を停止。書き込みのたびの再計算を防ぐ |
注意: 処理が終わったら必ず True / xlCalculationAutomatic に戻すこと。戻し忘れるとExcelの挙動がおかしくなる。エラーで処理が中断した場合も戻らないので、本番環境ではテクニック3のテンプレート(On Error GoTo付き)を使うことを推奨する。もしScreenUpdating=Falseのまま止まってしまった場合は、VBEのイミディエイトウィンドウで Application.ScreenUpdating = True を実行すれば復帰できる。
筆者の体験: この2行を追加するだけで、3000行の色分け処理が12秒から5秒になった。コードを1行も変えずに2倍以上速くなるので、まずはこれを試してほしい。画面更新停止の実例は /006(行の色分け)でも使用している。
—
テクニック2:配列で一括読み書き(最も効果大)
高速化の本命がこれ。セル範囲を配列(メモリ上のデータ)に一括で読み込み、配列上で処理し、結果を一括で書き戻す。
なぜ速いのか
セル直接操作の場合、1万行×4列 = 4万回のセルアクセスが発生する。配列なら、読み込み1回 + 書き込み1回の 計2回 で済む。アクセス回数が2万分の1になるので、速くなるのは当然だ。
コード
Sub 高速化_配列で処理()
Dim ws As Worksheet
Dim lastRow As Long
Dim arr As Variant
Dim i As Long
Set ws = ActiveSheet
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
' セル範囲を配列に一括読み込み
arr = ws.Range("A2:D" & lastRow).Value
' 配列上で処理(セルアクセスなし → 超高速)
For i = 1 To UBound(arr, 1)
' 例:D列(4番目)にA列×B列の計算結果を入れる
If IsNumeric(arr(i, 1)) And IsNumeric(arr(i, 2)) Then
arr(i, 4) = arr(i, 1) * arr(i, 2)
End If
Next i
' 配列をセルに一括書き込み
ws.Range("A2:D" & lastRow).Value = arr
MsgBox "完了しました。"
End Sub
最終行の取得について: ws.Cells(ws.Rows.Count, 1).End(xlUp).Row はA列の最終行を取得している。A列にデータがない場合は正しく取得できない。最終行の取得方法について詳しくは /032 を参照。
コードの読み方
| 行 | 意味 |
|---|---|
arr = ws.Range("A2:D" & lastRow).Value |
A2:D最終行のデータを配列に一括読み込み |
For i = 1 To UBound(arr, 1) |
配列の1行目から最終行までループ |
arr(i, 1) |
配列のi行目・1列目(= A列の値) |
arr(i, 4) = arr(i, 1) * arr(i, 2) |
D列にA列×B列の結果を代入 |
ws.Range("A2:D" & lastRow).Value = arr |
配列をセルに一括書き込み |
ポイント: 配列のインデックスは 1始まり。arr(1, 1) が最初のデータ(A2セルの値)になる。0始まりではないので注意。
—
テクニック3:全テクニックを組み合わせたテンプレート
テクニック1とテクニック2を組み合わせた、実務で使える完全版テンプレート。エラー時の設定復帰処理も入っている。
Sub 高速処理テンプレート()
Dim ws As Worksheet
Dim lastRow As Long
Dim arr As Variant
Dim i As Long
Dim startTime As Double
Set ws = ActiveSheet
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
If lastRow < 2 Then
MsgBox "データがありません。", vbExclamation
Exit Sub
End If
startTime = Timer
' === 高速化設定 ===
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
On Error GoTo ErrorHandler
' === 配列に一括読み込み ===
arr = ws.Range("A2:D" & lastRow).Value
' === 配列上で処理 ===
For i = 1 To UBound(arr, 1)
' ★ ここに処理を書く
If IsNumeric(arr(i, 1)) And IsNumeric(arr(i, 2)) Then
arr(i, 4) = arr(i, 1) * arr(i, 2)
End If
Next i
' === 配列を一括書き込み ===
ws.Range("A2:D" & lastRow).Value = arr
CleanUp:
' === 高速化設定を戻す(必ず実行される) ===
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
MsgBox "完了(" & Format(Timer - startTime, "0.00") & "秒)"
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました:" & Err.Description, vbCritical
Resume CleanUp
End Sub
コードのポイント
On Error GoTo ErrorHandler — エラーが発生したらErrorHandlerに飛ぶ。ErrorHandlerからCleanUpに飛ぶので、エラーが起きてもScreenUpdating=Trueなどの設定復帰が 必ず実行される。これが最も重要な安全対策。
筆者の体験: 以前、On Error GoToを入れずにマクロを実行中にエラーが出て、ScreenUpdating=Falseのまま止まったことがある。Excelの画面が真っ白になり、何も操作できなくなった。VBEのイミディエイトウィンドウで Application.ScreenUpdating = True を実行してようやく復帰できた。それ以来、高速化設定を使うときは必ずOn Error GoToを入れるようにしている。
Timer関数 — 処理前後の時刻差で経過秒数を表示する。高速化の効果を数値で実感できる。
EnableEvents = False — Worksheet_Changeなどのイベントプロシージャが設定されている場合、セルへの書き込みでイベントが発火する。Falseにしておけば余計な処理が走らない。イベントプロシージャの詳細は /008 を参照。
データ存在チェック — If lastRow < 2 Then で、ヘッダー行しかない(データがない)場合は処理を中断する。
---
なぜ配列は速いのか
VBAとExcelは別々のプログラムとして動いている。セルにアクセスするたびに、VBAとExcelの間でデータのやり取り(通信)が発生する。
セル直接操作のイメージ:
VBA → Excel「A2の値をください」 → Excel → VBA「150です」
VBA → Excel「B2の値をください」 → Excel → VBA「3です」
VBA → Excel「D2に450を書いてください」 → Excel「書きました」
(これを1万行分繰り返す = 4万回の通信)
配列のイメージ:
VBA → Excel「A2:D10001の全データをください」 → Excel → VBA「まとめて渡します」
(VBAのメモリ上で1万行分の計算を実行)
VBA → Excel「A2:D10001にまとめて書いてください」 → Excel「書きました」
(通信は2回だけ)
通信回数が4万回から2回に減る。これが配列が速い理由だ。
---
比較表:各テクニックの効果
どのテクニックをどの順番で使うべきか、まとめた。
| テクニック | 速度向上 | 導入の手軽さ | おすすめの場面 |
|---|---|---|---|
| ScreenUpdating=False | ×2.5 | 1行追加するだけ | まずこれを試す。すべてのマクロに入れてよい |
| Calculation=xlManual | ×1.5(追加) | 1行追加するだけ | 数式が多いブックで効果大 |
| EnableEvents=False | ×1.1(追加) | 1行追加するだけ | Worksheet_Changeなどのイベントがある場合 |
| 配列で一括読み書き | ×25 | コード構造の変更が必要 | 1000行以上のデータ処理で効果大 |
| 全テクニック併用 | ×40 | テンプレートをコピペ | 大量データ処理の定番パターン |
判断の目安:
- 数百行以下 → ScreenUpdating=Falseだけで十分
- 1000行以上 → 配列の導入を検討
- 1万行以上 → 配列 + 全テクニック併用を強く推奨
複数ファイルの統合処理(/005)や複数シートの一括処理(/015)でも、配列を組み合わせると大幅に高速化できる。
---
よくある落とし穴5選
| # | 症状 | 原因 | 対策 |
|---|---|---|---|
| 1 | マクロがエラーで止まり、Excelの画面が真っ白になった | ScreenUpdating=Falseのまま処理が中断した | On Error GoToでエラーハンドラを設け、CleanUpラベルで必ず ScreenUpdating=True に戻す。手動復帰はVBEのイミディエイトウィンドウで Application.ScreenUpdating = True を実行 |
| 2 | 配列のデータが1行ずれている | 配列のインデックスが1始まりなのに0始まりだと思ってコードを書いた | Range.Value で取得した配列は常に1始まり。arr(1, 1) が最初のデータ。不安なら LBound(arr, 1) で下限を確認する |
| 3 | 配列の書き込み後、データが消えた・余分な行が出た | 書き込み先のセル範囲が配列のサイズと一致していない | 書き込み前に UBound(arr, 1) で行数を確認する。書き込み範囲は「開始行 + UBound(arr, 1) - 1」で計算する。例:開始行が2なら Range("A2:D" & 2 + UBound(arr, 1) - 1) |
| 4 | マクロ実行後、シートの数式が自動計算されなくなった | Calculation=xlCalculationManualのまま処理が終了した | On Error GoToで必ず xlCalculationAutomatic に戻す。手動復帰は「数式」タブ→「計算方法の設定」→「自動」 |
| 5 | 配列内の空セルで「型が一致しません」エラーが出る | 空セルはVariant配列で Empty になり、数値演算すると型不一致エラーになる |
IsEmpty(arr(i, 1)) または IsNumeric(arr(i, 1)) で判定してから計算する |
筆者の体験: 落とし穴1は本当によくやる。特に開発中はエラーが頻発するので、On Error GoToを入れずにScreenUpdating=Falseを使うと、エラーのたびにExcelが固まる。テクニック3のテンプレートには最初からOn Error GoToを入れてあるので、コピペして使えばこの問題は起きない。
VBAで配列に読み込んだデータがずれるときの対処法
「配列のデータが1行ずれている」という場合、原因は配列のインデックスが0始まりだと思い込んでいることだ。Range.Value で取得した配列は常に1始まり(arr(1, 1) が先頭)。不安なら LBound(arr, 1) と UBound(arr, 1) で範囲を確認してからループすれば安全だ。
VBAでScreenUpdating=Falseのまま画面が固まったときの対処法
「マクロがエラーで止まりExcelの画面が真っ白になった」という場合、原因はScreenUpdating=Falseが復帰されていないことだ。VBEを開き(Alt+F11)、イミディエイトウィンドウ(Ctrl+G)で Application.ScreenUpdating = True と入力してEnterを押せば復旧する。On Error GoToで必ず復帰処理を入れるのが予防策だ。
---
FAQ
Q1: 既存のマクロに配列を導入するのは大変?
基本パターンは3ステップ。(1) セル範囲を配列に読み込む (2) Cells(i, j) を arr(i, j) に書き換える (3) 配列をセルに書き戻す。セル参照を配列参照に置き換えるだけなので、コード全体を書き直す必要はない。既存マクロの書き換えが難しい場合はココナラで相談できます。
Q2: ScreenUpdating=Falseだけで十分では?
小規模データ(数百行)なら十分。ただし1万行以上では配列の効果が圧倒的。ScreenUpdating=Falseは×2.5の高速化だが、配列は×25。10倍以上の差がある。大量データを扱うなら配列を使うべき。
Q3: 配列が使えないケースはある?
セルの書式(背景色・フォント・罫線など)を変更する処理は配列では扱えない。配列で扱えるのはセルの「値」のみ。書式変更が必要な場合はセルアクセスが必要だが、ScreenUpdating=Falseは併用できる。行の色分け処理(/006)ではScreenUpdating=Falseが有効。
Q4: 処理時間を計測する方法は?
Timer関数を使う。テクニック3のテンプレートに処理時間の計測が組み込まれている。実行すると「完了(0.23秒)」のようにMsgBoxで表示される。
Dim startTime As Double
startTime = Timer
' 処理
MsgBox Format(Timer - startTime, "0.00") & "秒"
Q5: 10万行以上のデータでも配列で処理できる?
可能。Variant配列のメモリ使用量は概算で行数×列数×16バイト程度。10万行×10列でも約15MB。一般的なPCのメモリ(8GB以上)なら問題ない。ただし100万行を超える場合は分割処理を検討する。処理の進捗表示が必要な場合は /026 を参照。
---
まとめ
この記事では、VBAの処理速度を10倍以上に改善する3つのテクニックを解説した。
- テクニック1:ScreenUpdating=False + Calculation=xlManual → 約2.5倍速。1行追加するだけ
- テクニック2:配列で一括読み書き → 約25倍速。最も効果が大きい
- テクニック3:全テクニック併用テンプレート → 約40倍速。エラー時の設定復帰付き
大量データを扱うマクロでは、テクニック3のテンプレートをそのまま使うのがおすすめ。
関連記事:
- /005 複数Excelファイルの統合 — 配列と組み合わせると統合処理も高速化できる
- /015 複数シートの一括処理 — シートループ×配列で大幅に速くなる
- /026 進捗表示 — 長時間処理の進捗バーを表示する方法
- /032 最終行の取得 — 配列の範囲指定に必須のテクニック
次にやりたくなること:
- /032 最終行の正確な取得方法を知りたい — 配列の範囲指定に必須のテクニック
- /026 長時間処理の進捗バーを表示したい — 配列処理でも進捗が見えると安心
- /005 複数Excelファイルの統合を高速化したい — 配列と組み合わせて統合処理も一気に速くなる
- /022 エラー処理で止まらないマクロにしたい — 配列処理中のエラーでScreenUpdatingが戻らない問題を防げる
- /015 全シートに配列処理を一括適用したい — シートループ×配列で大量シートの処理を劇的に高速化
---
もっとカスタマイズしたい場合
「既存のマクロを配列に書き換えて高速化したい」「大量データの処理を自動化したい」「10万行以上のデータを分割処理したい」など、業務に合わせたカスタマイズが必要な場合は、ココナラで相談できます。
相談時に以下の情報があるとスムーズです:
- Excel のバージョン / OS
- 現在のマクロの処理内容(何をしているか)
- データの行数・列数(目安)
- 現在の処理時間と目標時間


コメント