動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

Excel VBA が数万行で固まる時の高速化7選 — Range を配列に読んで一括処理する

バイブス父さん
現役の業務SE
2026年9月17日12 min read広告 (PR) を含む場合があります
Excel VBA が数万行で固まる時の高速化7選 — Range を配列に読んで一括処理する

みなさんこんにちは、ヒロポンです!

Excel のマクロ、数万行になった途端に固まりませんか??

セルを1つずつループして処理するやつ。1000行なら一瞬です。それが5万行を超えたあたりで数分かかる。下手すると応答なし。原因ははっきりしてます。直し方にも定石がある。

今回は、数万行で固まる VBA を速くする7つのポイントを、実務で効く順にまとめました。核は「Range を配列に一括で読む」の1点。ここを押さえるだけで桁が変わります。コピペで動く形で置いていくので、手元の遅いマクロに当てていってください。

なぜ数万行で固まるのか

犯人は主に2つ。

1つめが、セル(Range)への逐次アクセスCells(i, 1) みたいにセルを1個触るたびに、VBA と Excel 本体の間でやり取りが走ります。え、そんなに重いの??って思うくらい1回は軽いんですが、それが5万回積み上がると効いてくる。セルを触った回数が、そのまま処理時間に乗るイメージです。

2つめが、画面の再描画と自動再計算。ループ中にセルへ書き込むたび、画面が描き直されて数式が再計算される。これも1回ずつは軽い。数万回で地獄になります。

裏を返せば、この2つを潰せば速くなる。順に見ていきます。

⏱ 高速化インパクト早見表

先に効果の目安を1枚で。上から効きます。

VBA高速化7手法(Range配列一括/ScreenUpdating停止/Calculation手動/EnableEvents停止)の止める対象・効果の目安・難易度を比較した早見表

配列一括だけ難易度が「中」です。効果が段違いなので最優先。では1つずつ。

1. Range を配列に一括読み込みする(最重要)

一番効くのがこれ。セルを1個ずつ触るのをやめて、範囲まるごと Variant 配列に読み込みます。

配列に入れてしまえば、あとはメモリ上の計算です。メモリ上のループは、セルを触るのに比べて桁違いに速い。処理が終わったら、また範囲まるごと1回で書き戻す。この「読むのも書くのも1回ずつ」が効きます。

セルを1つずつループして遅い書き方と、Rangeを配列に一括で読んでメモリ上で処理し一括で書き戻す速い書き方の差分

やり取りが「5万回 → 2回」になる。これが桁違いの正体です!!

扱う範囲が広いほど、この差は開きます。1万行では速さを感じなくても、10万行になると「数分 → 数秒」くらいの差になることも珍しくない。

教訓: セルを回すな、配列を回せ。

2. Application.ScreenUpdating を False にする

ループ中の画面のチラつき、あれ全部描き直してます。処理の間だけ止めましょう。

Application.ScreenUpdating = False
' ここで重い処理
Application.ScreenUpdating = True   ' 終わったら忘れず戻す

こんな感じで挟むだけ。配列一括と併用すると、さらに効きます。

教訓: 処理中は画面を描かせない。

3. Application.Calculation を Manual にする

数式がたくさん入ったシートだと、セルに書き込むたびに全再計算が走る。これを手動に切り替えて止めます。

Application.Calculation = xlCalculationManual
' ここで重い処理
Application.Calculation = xlCalculationAutomatic  ' 終わったら戻す

数式が多いシートほど効きます。数式ゼロのシートなら、ここは効果薄です。

教訓: 数式が多いなら再計算を止める。

4. Application.EnableEvents を False にする

Worksheet_Change みたいなイベントを仕込んでる場合、書き込みのたびにそのイベントが発火します。処理中は止めておく。

Application.EnableEvents = False
' ここで重い処理
Application.EnableEvents = True   ' 終わったら戻す

イベントを使ってないブックなら、ここは無くてもいい。使ってる時だけです。

教訓: 自作イベントがあるなら止める。

5. 1〜4 を1つのテンプレにまとめる

毎回書くのは面倒なので、ひな形にしておくと楽です。エラーで中断しても設定が戻るように、On Error も入れておきます。

Sub FastProcess()
    ' 描画・再計算・イベントを止める
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False

    On Error GoTo Cleanup   ' 途中でコケても戻す

    Dim data As Variant
    data = Range("A1:C50000").Value   ' 一括読み込み(2次元・1始まり)

    Dim r As Long
    For r = 1 To UBound(data, 1)
        data(r, 3) = data(r, 1) * data(r, 2)   ' メモリ上で計算
    Next r

    Range("A1:C50000").Value = data   ' 一括書き戻し

Cleanup:
    ' 戻し忘れると Excel が重いままになるので忘れずに
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
End Sub

この形の肝は On Error GoTo Cleanup です。処理の途中でエラーが出ても、Cleanup: のラベルに飛んで、止めた設定を戻してから終われます。これが無いと、エラーで中断した瞬間に画面更新も再計算も止まったまま放置される。Excel が重いままになります。

いい感じに使い回せます。中身の処理だけ差し替えれば、たいていのマクロがこの形に収まる。

教訓: 戻す処理は Cleanup にまとめて漏れなく通す。

6. 配列は「1始まり」で回す(落とし穴)

ここからは、速くしたあとに踏む落とし穴です。

Range.Value で受けた配列は、行も列も1始まりの2次元配列になります。Dim data(0 To ...) みたいな0始まりのクセで data(0, 0) と書くと、最初の行が抜けたり、範囲外エラーになったりする。

Dim data As Variant
data = Range("A1:C100").Value

' ん? 0 から回すと1行目が抜ける
' For r = 0 To UBound(data, 1) - 1  ← これはダメ

' 1始まりで回す。範囲は LBound / UBound で取ると安全
Dim r As Long
For r = LBound(data, 1) To UBound(data, 1)
    ' data(r, 1) が1列目、data(r, 2) が2列目…
Next r

LBound / UBound で範囲を取っておけば、始まりが何であれ事故りません。

教訓: Range 由来の配列は1始まり。範囲は LBound / UBound で。

7. 配列の「型」に注意する(落とし穴)

配列に読み込むと、セルの中身が Variant の中で色々な型になります。ここが最後の罠。

  • エラー値#N/A #DIV/0! など)… Variant のエラー型で入る。そのまま計算すると実行時エラー
  • 日付Date 型で入るので、数値のつもりで足すと想定とズレることがある
  • 空セルEmpty で入る。計算では0扱いだが、文字列結合だと空文字
  • 文字列として入った数値 … 見た目は数字でも、文字列として格納されている列がある。10001,000 は掛け算のときに暗黙変換されることが多いが、$1,000 のように数値化できない書式が混じると型不一致(実行時エラー 13)になり得る。ここは挙動が環境で変わるので、実機で確認しておくと安全

配列にした瞬間、中身は Variant の寄せ集めになる、ということです。見た目が数字でも、中身は文字列やエラー。これが普通にあります。

こんな感じで型がバラつくので、エラー値が混じる可能性がある列は IsError でよけてから触ります。

Dim r As Long
For r = 1 To UBound(data, 1)
    If IsError(data(r, 1)) Then
        data(r, 3) = 0            ' エラーセルは0などで逃がす
    Else
        data(r, 3) = data(r, 1) * 1.1
    End If
Next r

速くはなったのに、#N/A 1個で全体が止まる。よくあるハマり方です。実データを流す前に、エラー値と空セルの扱いだけは決めておくと安全。

ひとつ注意。IsError#N/A などのエラー値専用で、文字列として入った数値(テキスト数値)は捕まえられません(IsError("1,000") は False)。「数値として計算できるか」を確かめたいなら、IsError ではなく IsNumeric() で判定します。

' テキスト数値かどうかは IsNumeric で見る
If IsNumeric(data(r, 1)) Then
    data(r, 3) = CDbl(data(r, 1)) * 1.1  ' 数値化してから計算
Else
    data(r, 3) = 0                        ' 数値化できないものは逃がす
End If

まとめ: 高速化チートシート

数万行で固まる VBA は、この順で当てれば速くなります。

  1. Range を配列に一括読み込み(最優先・桁違い)
  2. ScreenUpdating = False(画面を描かせない)
  3. Calculation = Manual(再計算を止める・数式が多い時)
  4. EnableEvents = False(自作イベントがある時)
  5. 1〜4 をテンプレ化(Cleanup で忘れず戻す)
  6. 配列は1始まり(LBound / UBound で回す)
  7. 型に注意(エラー値は IsError・テキスト数値は IsNumeric でよける)

私も昔、セル逐次で書いた集計マクロが数万行で数分固まって、上司の前で「応答なし」を出したことがあります。冷や汗ものでした。配列一括に直したら数秒。あの時ほど「セルを回すな、配列を回せ」を体で覚えたことはないです。

配列一括処理を押さえるだけで、Excel マクロは体感で桁が変わります。遅いマクロを1本、これで直してみてください。

動作確認メモ: この記事の VBA コードは構文とロジックのレビューまでです(VBA は Excel + Windows の実機が必要なため、Docker での実行確認はしていません)。実環境(Excel の VBE)での通し動作は、お手元でも確認してください。

よくある質問

VBA でセルを1つずつ処理すると、なぜ数万行で固まるのですか?

セル(Range)へのアクセスは1回ごとに Excel 本体とやり取りが発生し、これが数万回繰り返されると累積で非常に遅くなるためです。Range を Variant 配列に一括で読み込めば、やり取りは読み込みと書き戻しの2回で済み、桁違いに速くなります。

Range から読み込んだ配列の添字は0始まりですか、1始まりですか?

1始まりです。Range.Value で受けた Variant 配列は、行・列とも1始まりの2次元配列になります。0から回すと最初の行が抜けるので、LBound / UBound で範囲を取るのが安全です。

ScreenUpdating や Calculation は元に戻さないとどうなりますか?

FalseManual のままマクロが終わると、Excel の画面更新や自動再計算が止まったままになり、以降の操作が重く感じられます。エラーで中断しても戻るように、On Error GoTo で忘れず元に戻す処理を入れておきます。

配列に読み込むと壊れるデータはありますか?

エラー値(#N/A など)を含むセルは Variant のエラー型として入り、そのまま計算するとエラーになります。日付や空セルも型が想定と変わることがあるので、IsError などでチェックしてから処理します。

次に読むべき記事

以上!

同じ「マクロが数万行で固まる」で悩んでる人がいたら、この記事シェアしてくれると嬉しいです!!


執筆者

バイブス父さん — 業務 SE 7 年(SIer 正社員 2 / フリーランス 5)。現職は SEO 直轄部の AI アドバイザー兼 PL、副業で中小 SIer の CTO。SIer の正社員からフリーランスに転じ、複数のエージェント経由で案件を回してきた経験ベースで「業務 SE 視点」の技術 + キャリア記事を書いています。

🐦 X: @hiro_progra0524(日々の現場メモ更新中)
📝 About Me で経歴詳細を見る


この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について