VBAで数千行のデータを処理するとき、ループの回数を意識せずに書くと処理が遅くなったり、無駄な繰り返しが大量に発生したりします。少しの工夫でループ回数を減らすだけで、処理速度が数倍になることもあります。
この記事では、ループ回数を減らすための3つのアプローチ(最終行の限定・SpecialCellsの活用・配列への一括読み込み)を具体例で解説します。
最終行を取得してループ範囲を絞るには?
固定の行数でループするコードは、データが少ない場合に無駄なループが大量発生します。
' 改善前:1000行固定で回す(データが100行でも900回無駄)
For i = 2 To 1000
If Cells(i, 1).Value <> "" Then
Cells(i, 2).Value = "済"
End If
Next i
' 改善後:A列の最終行まで限定する
Dim i As Long
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
If Cells(i, 1).Value <> "" Then
Cells(i, 2).Value = "済"
End If
Next i
Cells(Rows.Count, 1).End(xlUp).Row でA列の最終行番号を取得し、そこまでしかループしないようにします。データが増減しても自動的に対応できます。
SpecialCellsとFor Eachで対象セルだけを処理するには?
さらに効率化したい場合は、SpecialCells で「値が入っているセルだけ」を取り出してループする方法があります。
Dim rng As Range
Dim c As Range
Set rng = Range("A2:A1000").SpecialCells(xlCellTypeConstants)
For Each c In rng
c.Offset(0, 1).Value = "済"
Next c
SpecialCells(xlCellTypeConstants) は値が入っているセルだけを範囲として返します。空白セルを完全にスキップするため、ループ回数が大幅に減ります。
For Each は数値カウンターではなく「存在する対象」を1つずつ取り出して処理する構文です。対象が明確なときにコードが読みやすく、エラーも出にくい書き方です。
配列に一括読み込みして処理するには?
処理速度を最大限に上げたい場合は、セル範囲を一度配列に読み込み、配列内で処理してからまとめて書き戻す方法が最も効果的です。
Dim data As Variant
Dim i As Long
' セル範囲を配列に一括読み込み
data = Range("A2:A1000").Value
' 配列内で処理する(Excelシートへのアクセスなし)
For i = 1 To UBound(data, 1)
If data(i, 1) <> "" Then
data(i, 1) = "済"
End If
Next i
' 処理結果をまとめてシートに書き戻す
Range("A2:A1000").Value = data
ポイントは次の3つです。
Variant型の変数はあらゆるデータを格納できる柔軟な型で、セル範囲を二次元配列として受け取れるdata(行, 列)の形で各セルに相当する値にアクセスする(例:data(1, 1)は1行目1列目)UBound(data, 1)で配列の行数(ループの終端)を取得する
Excelシートとのやりとり(読み書き)を最初と最後の1回ずつに抑えることで、数千行の処理でも圧倒的に高速になります。
まとめ
lastRow = Cells(Rows.Count, 1).End(xlUp).Rowでループ範囲をデータが存在する行だけに絞るSpecialCells(xlCellTypeConstants)とFor Eachで値が入っているセルだけを対象にする- 配列に一括読み込み → 配列内で処理 → まとめて書き戻すの流れが最も高速
- 固定行数のループは「データが少ない状況での無駄なループ」の原因になりやすい
- ループ回数の削減は処理速度だけでなくコードの可読性向上にもつながる
よくある質問
SpecialCellsで対象セルが1つもない場合にエラーになりますか?
なります。SpecialCells は対象セルが存在しないとエラーになるため、On Error Resume Next でエラーを回避するか、事前にデータの有無を確認する処理を入れておくと安全です。
配列を使う方法はどのくらい速くなりますか?
1行ずつセルに書き込む方法と比べて、数百〜数千倍速くなるケースもあります。特に1万行を超えるような大量データを扱う場合に効果が顕著です。
ForとFor Eachはどう使い分けますか?
繰り返す回数が決まっているときや行番号で制御したいときは For i = 開始 To 終了、セル・シートなどのコレクションの各要素を処理するときは For Each が適しています。
配列の二次元インデックス(data(i, 1))の意味が分かりません。
セル範囲を配列に取り込むと「行×列」の二次元配列になります。data(i, 1) は「i行目の1列目」を意味します。A列だけを読み込んだ場合、列インデックスは常に1になります。
Application.ScreenUpdatingと組み合わせるとさらに速くなりますか?
はい。配列処理と Application.ScreenUpdating = False を組み合わせると、画面の再描画も止まるためさらに高速になります。処理後に True に戻すことを忘れないようにしましょう。
動画で学びたい方へ
「記事を読んでも、実際に自分で書けるか不安…」という方には、動画で基礎からじっくり学べる講座がおすすめです。
VBAが初めての方を前提に、つまずきやすいポイントを先回りして解説しています。サンプル動画は無料でご覧いただけます。



