セル参照のRangeとCellsは使い分けをした方がよいが、、

VBAでセルを参照する際にRangeプロパティかCellsプロパティのどちらかを使うことになります。

その際に、Cellsプロパティだけで実装することも、Rangeプロパティだけで実装することも可能です。

しかし、このようにかなり融通は利くのですが、状況に応じて適切に使い分けを行うことで処理速度が変わってきます

ただ、そんなに変わりません。


単一セルはCells、複数セルはRangeを使うと速い

結論から言うと、単一セルの場合はCellsプロパティを使い、複数セルの場合はRangeを使うようにするのが一番処理速度は速いです。

ただし、劇的に速くなるようなことにはなりません。

各条件ごとに速度の違いについて後述します。

ただし、処理速度が一番速い書き方にこだわる必要はない、というのが私の考えです。

それについても後述します。


RangeとCellsの使い分け

RangeプロパティとCellsプロパティは厳密に用途が異なります。

Rangeプロパティの用途

Rangeプロパティは以下の2つの用途で使います。

・単一セルをA1形式で参照する場合(Range(“A1”))
・複数セルやセル範囲を参照する場合(A1~B2セルを参照:Range(“A1:B2”)、A~C列を参照:Range(“A:C”)、A1~B2範囲とC3~D4範囲を参照:Range(“A2:B2,C3:D4”))

Cellsプロパティの用途

・単一セルを行番号と列番号を指定して参照する場合(A2セルを参照:Cells(2, 1))


単一セルの参照はCellsの方が速い

単一セルを参照する場合は、Cellsプロパティの方が速いです。

その理由ですが、座標の文字列変換があるかないかの違いと思われます。

Cellsプロパティは行番号と列番号を数値で指定するため、数値がそのままシートのセル座標に置き換えて処理が可能ですが、Rangeプロパティは、”A1″という文字列でセル位置を指定するため、英字部分と数字部分に切り分けて、英字から列番号位置を算出して、行番号文字列と列番号も列をそれぞれ数値に変換してセル座標の置き換え、という流れを行っているものと思われます。

この変換処理の分、RangeプロパティはCellsプロパティよりも時間が掛かります。

以下のソースで実測してみました。

A1セルを参照する処理をRangeとCellsのそれぞれ1万回行っています。

計測には高精度時間を算出する関数を利用しています。

実測結果は、Rangeが1.5秒、Cellsが1.44秒と、Cellsの方が若干速いです。

Range:1.50643464864697秒
Cells:1.44152700668201秒


Range(“A” & CStr(iRow))と書くと遅い

例えばRange(“A1”)からRange(“A100000”)までのループ処理で、1から100000の部分をループカウンタで代用することがあります。

こんな書き方ですね。

先に書いた内容と同じですが、Rangeの場合は構文解析が行われることにより処理速度が遅くなります。

以下のようにCellsに書き換えた方が処理速度は速くなります。

どれぐらい速くなるのか確認してみます。

実行結果はこうなりました。

Range:15.3357434456702秒
Cells:11.3562810394214秒

ループカウンタの100000を10000に変更すると実行結果はこうなりました。

Range:3.32276758423541秒
Cells:2.35987033683341秒

単純には言えませんが、Cellsに比べて1.4倍程度Rangeの方が時間が掛かっています。


Range(“xx”).Offsetは遅い

私もよく使うOffsetですが、Cellsと比べると処理は遅いです。

基点からの指定行列位置を求める必要があるため、直接アドレスを指定するCellsよりも遅くなります。

これも実測してみます。

実測結果です。

Cellsに比べて1.65倍ほどRangeの方が時間が掛かっています。

Range:3.71202648698818秒
Cells:2.24162556300871秒


でも、単一セルにRangeやOffsetを使っても構わない

処理速度の向上を目的として書いた記事ではありますが、個人的にはRangeとCellsに関して言えば「慣れている書き方」や「好きな書き方」を優先させて処理速度を犠牲にしても構わないと思っています。

この記事で言えば、単一セルやOffsetでRangeは使わずにCellsを使った方が処理速度は速くなります、と書いてますが、単一セルやOffsetでRangeを使っても全然いいと思います。

現に私はCellsの方が速いと分かっていても、マクロを作る際にRange(“A” & CStr(i))やOffsetを多用します

VBAに限らずあらゆるプログラミング言語で処理速度向上を行う方法がありますが、個人的には処理速度向上は目的に対する優先度としてはそんなに高くありません

ここで言う目的とは、以下に挙げるようなマクロを作って行う何らかの自動化、を指します。

  • 1回しか動かさないマクロなんで処理速度とかどうでもいい。
  • ループが10回程度なんでRangeでもCellsでもほとんど変わらないし気にもしない。
  • Range(“A” & CStr(i))と書く方がA列なのがはっきりして分かりやすい。
  • Offsetを使った方が紙の資料と見比べながらマクロを書く際に分かりやすい

などなど、コードを書くときの状況やコードを書いた人の考え方はバラバラです。

その状況によって何が優先されるのかは変わりますので、ガチガチに「処理速度が速い方法で書け!」なんてことを言ってるのは違うと思います。

そして上でも実測結果を挙げましたが、速いといってもある程度、というぐらいのものです。ついでに言えば、数秒程度の差であればパソコンが新しくなるだけで差も小さくなっていきます。

処理速度をより速くするのは、それ自体は良いことですが、それよりも大事なことがある場合はそちらを優先しましょう