Access VBAの世界へようこそ。
「なぜかプログラムの動作が重い」「レコードを1000件処理するだけで、コーヒーを飲みに行けるくらい時間がかかる」。そんな悩みを持つあなたへ。今日は、Access VBAにおける「最適化の第一歩」であり、伝説のエンジニアたちが必ず通る道である「CurrentDbのキャッシュ」についてお話しします。
ここを理解すれば、あなたのコードは「書き殴ったメモ」から「洗練されたシステム」へと進化します。
—
1. なぜ「CurrentDb」をループに入れてはいけないのか
多くの初心者が、データの読み書きを行う際に以下のようなコードを書いてしまいます。
‘ 【悪い例】ループのたびにCurrentDbを呼び出している
For i = 1 To 1000
CurrentDb.Execute “INSERT INTO T_ログ (ログ内容) VALUES (‘テスト’)”
Next i
一見、何の問題もなさそうに見えますね。しかし、このコードは「毎回、家の表札を確認してから家に入る」という非効率な行為を繰り返しています。
`CurrentDb` を呼び出すたびに、Accessは内部で「現在開いているデータベースはどこだ?」「権限はあるか?」「接続オブジェクトを生成せよ」という重厚な手続きを裏側で行っています。1000回呼び出せば、その分だけ無駄なコストが発生し、CPUとメモリを不必要に浪費しているのです。
—
2. 解決策:DAO.Database変数のキャッシュ
「一度呼び出したものは、手元に置いておく」。これがプログラミングの鉄則です。`CurrentDb` を変数に入れて使い回すだけで、劇的に速度が改善します。
基本的な書き方
Sub FastDatabaseAccess()
‘ DAO.Database型の変数を宣言(これがキャッシュ用の器です)
Dim db As DAO.Database
Dim i As Long
‘ 最初に一度だけCurrentDbをセットする
Set db = CurrentDb
‘ ループ内ではセット済みの変数を使う(これが高速化の秘訣!)
For i = 1 To 1000
db.Execute “INSERT INTO T_ログ (ログ内容) VALUES (‘No.” & i & “‘)”, dbFailOnError
Next i
‘ 使い終わったら解放する(メモリ管理の作法)
Set db = Nothing
End Sub
なぜこれで速くなるのか?
`Set db = CurrentDb` とした瞬間、Accessはデータベースへの接続情報をメモリ上の `db` という変数に保持します。ループの中では、その「メモリ上の住所」を直接参照するだけなので、毎回データベースの接続情報を再生成する必要がなくなるのです。
—
3. 実践で必ず守るべき「3つのルール」
このテクニックを現場で使う際、以下のルールを覚えておいてください。
① `dbFailOnError` を添える
`db.Execute` を使う際は、必ず第二引数に `dbFailOnError` を指定してください。これがないと、SQLの途中でエラーが起きてもAccessは「成功したふり」をして黙り込んでしまいます。バグの温床を断つための必須オプションです。
② 明示的に `Nothing` を代入する
`Set db = Nothing` は、VBAにおける「後片付け」です。小さなプログラムなら自動的に解放されますが、大規模なシステム開発では、この一行がメモリリーク(メモリの食いつぶし)を防ぐ命綱になります。
③ 変数名はシンプルに
慣れてくると `db` 以外の名前(`ws` や `dbCurrent` など)を使う人もいますが、`db` がAccessエンジニア界隈の共通言語です。あえて奇をてらう必要はありません。
—
最後に:プロのエンジニアへの第一歩
「CurrentDbをキャッシュする」。たったこれだけのことですが、この意識の差が、「動くコード」と「強いコード」の分かれ道です。
- 毎回呼び出す:無駄な手続きの連続。
- キャッシュする:一度の手続きで、あとはスマートに処理。
Access VBAは、こうした小さな積み重ねが、驚くほどのパフォーマンスを生み出す言語です。まずは今書いているコードの `CurrentDb` を探し出し、変数に置き換えてみてください。その瞬間に、あなたのプログラムが少しだけ、軽やかで強固なものに変わるはずです。
もし分からないことがあれば、いつでも聞いてください。ここをクリアしたあなたは、もう初心者ではありません。次のステップへ進む準備は万端ですよ。
