処理は低速であるが、Databaseオブジェクトを毎回生成するような代替関数を使うよりは高速である。Databaseオブジェクトの生成にはかなりのオーバーヘッドがかかるので、それさえうまく回避できれば、定義域集計関数を使うよりも代替のSQLを使ってレコードセットから結果を得た方が高速に処理できる。呼ばれ、一般的には低速な関数といわれています。それらの関数は、すべてまったく同等の処理をSQLで行なうことができます。ここでは、それらを実際に比較することによって、本当に定義域集計関数が遅いのか、またSQLによるものとどれくらい違うのかを確認してみたいと思います。ここでは、DLookup関数とDCount関数の2つについて比較してみます。テストパターンとして次のような3つを用意しました。同等の、SQLによる代替のオリジナル関数を呼び出した場合(Databaseオブジェクトの生成も毎回行なう)代替のSQL文を関数化せずに同じプロシージャ内で実行した場合(Databaseオブジェクトの生成は一度だけ行なう)それぞれのテストパターンについて、同じ呼び出しをループで1万回ずつ行ない、その総処理時間を比較するものとします。テスト用のコードは次のようなものです。Functionメインプロシージャ「Test」で各テストパターンの呼び出しを行ないます。このプロシージャ内では、3番目のテストパターン用に、CurrentDb関数を使ってDatabaseオブジェクトを生成しています。この部分の生成時間はテスト結果には含めません。「DLookupTest」と「DCountTest」の2つのFunctionプロシージャは、それぞれDLookup関数、DCount関数と同等の処理行なうもので、SQL文によってそのレコードセットを生成し、得られた1レコードのフィールド値を返します。これらのプロシージャでは、呼び出されるたびにCurrentDb関数によってDatabaseオブジェクトが生成され、その処理時間もテスト結果に含まれることになります。ここで用いられているSQL文はあらかじめテーブル名やWhere条件が固定されており、あくまでもテスト用に簡略されたもので、厳密にはDLookup関数などの代替とはいえません。定義域集計関数のように、さまざまなテーブル名やWhere条件に対応させるとそれなりに処理が増えますので、正確には実行結果の時間が増える可能性があります。テストの実行はメインプロシージャ「Test」を1回実行するだけです。その結果は次のようになりました。テストパターン実行時間(秒)DLookupDLookup関数28.8DLookupの代替関数34.3SQLによるDLookupの代替18.1DCountDCount関数29.9DCountの代替関数34.3SQLによるDCountの代替18.3ご覧のように、明らかな時間の差が出ています。高速なのはDatabaseオブジェクトの生成を1回だけ実行した場合のSQLによる代替処理です。それに比べると時間はかなりかかっていますが、2番目に速いのは通常の定義域集計関数でした。定義域集計関数よりは速いのではないかと予想していた独立したプロシージャの代替関数は、もっとも遅いという結果になりました。これらのことから、確かに定義域集計関数の処理は低速であるが、Databaseオブジェクトを毎回生成するような代替関数を使うよりは高速であるということがいえます。Databaseオブジェクトの生成にはかなりのオーバーヘッドがかかるようで、それさえうまく回避できれば、定義域集計関数を使うよりも代替のSQLを使ってレコードセットから結果を得た方がかなり高速に処理できるということも分かります。上記の「Test」プロシージャのように、CurrentDb関数を1回使ったあと、さまざまな定義域集計関数を使いたいようなケースでは、SQL文を使った方法がかなり有効です。してもFunctionプロシージャ化された代替関数を使いたい場合には、上記コードでの「dbs」という変数をPublicな変数として宣言し、一連の処理を実行する前にその値を設定しておくことで、対処可能です。各Functionプロシージャ内ではCurrentDb関数は実行せず、そのPublicな「dbs」変数を使うようにします。今回Where条件として使った「会社名」というフィールドには一切キーは設定してありません。よってそれがキー付きのフィールドであった場合には、当然SQLの実行では速くなることが予想されますし、定義域集計関数も速くなる(もしかしたら遅くなるかも)可能性もありますので、場合によっては差異がなくなるかもしれません。それらはケースバイケースとして別途テストが必要かもしれません。