#18 For〜NextとFor Each〜Nextを比較する

結論
コレクションに属する個々の要素を列挙する場合には「For〜Next ステートメント」の方が「For Each〜Next ステートメント」よりも高速である。

Accessには同じ種類のオブジェクトの集まりを表す「コレクション」という概念があります。例えば、データベースは複数のテーブルや複数のフォーム、複数のレポートなどから構成されています。1つのテーブルは複数のフィールドの集まりです。1つのフィールドはさまざまなプロパティ(属性)が集まることによってその特性が決められています。またフォームも複数のコントロールが集まって構成されていますし、1つ1つのコントロールもまたさまざまなプロパティの集合体です。

コレクションに属する個々の要素を順番に抜き出して一連の処理を行いたい場合に便利なのが「For Each〜Next ステートメント」です。このステートメントの使用にあたっては、コレクション内の要素数を知ることなくすべての要素を列挙することができます。また、個々の要素はあらかじめ宣言されたオブジェクト変数(fld As Field...など)に自動的に代入されます。

ところで、このコレクションもまた1つのオブジェクトであり、いくつかのプロパティを持っています。その中の[Count]プロパティを調べることによってコレクションに含まれる要素数を取得することができます。また、コレクションの各要素はゼロから始まるそれぞれ一意のインデックスを持っています。したがって、[Count]プロパティをループの上限値として、またループカウンタ変数を要素のインデックス値として扱うことによって、「For〜Next ステートメント」によってもコレクション要素の列挙を行うことができます。

そこでここでは、あるテーブルを構成する"フィールドの集まり"である[Fields]コレクションについて、すべての要素名つまり"フィールド名"を列挙するプログラムを For Each〜Next を使った場合と For〜Next を使った場合とで、その処理時間を測定・比較してみたいと思います。

テストコードは次のようなものです。

  Dim dbs As Database
  Dim tdf As TableDef
  Dim fld As Field
  Dim strFldName As String
  Dim intFldLoop As Integer
  Dim iintLoop As Integer
  Const clngTestCnt As Long = 1000  'テスト回数のループカウンタ
  
  Set dbs = CurrentDb
  Set tdf = dbs.TableDefs("tblFieldTest")
  
  ts_Watch "テスト開始", True
  For iintLoop = 1 To clngTestCnt
    For Each fld In tdf.Fields
      strFldName = fld.Name
    Next fld
  Next iintLoop
  ts_Watch "For Each〜Next"
  
  For iintLoop = 1 To clngTestCnt
    For intFldLoop = 0 To tdf.Fields.Count - 1
      Set fld = tdf.Fields(intFldLoop)  '添え字は0から始まる
      strFldName = fld.Name
    Next intFldLoop
  Next iintLoop
  ts_Watch "For〜Next"

そして、テスト結果はつぎのようなものになりました。
Do〜Loop 2.54 Sec
For〜Next 1.72 Sec
コレクションの要素を扱う方法の例ではしばしば「For Each〜Next ステートメント」が出てきて、あたかもそれがお決まりの手法のように思っていましたのでこれは意外な結果でした。明らかに"コレクションに属する個々の要素を列挙する場合には「For〜Next ステートメント」の方が「For Each〜Next ステートメント」よりも高速である。"という結果になっています。

上記のテスト結果はあくまでも1000回ものテストの累積時間差です。実際には、あらゆるVBAのコードで For〜Next が使われる頻度に比べてコレクションを扱う頻度は極端に少ないでしょうし、コレクションを扱う場合にも要素数もそう多くないと思われます。そう考えると上記の結果は「コレクションでは For〜Next を使うべし」と言うほどではないでしょう。簡単なコードで済ませたい場合には For Each〜Next、ループの中でループカウンタ変数を要素の添え字以外にも使いたいような場合には For〜Next、と状況に応じて使い分ければいいと思います。
| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved