こんにちは! Access VBAでの開発、日々の試行錯誤お疲れ様です。
マクロの記録から一歩踏み出し、「自分でコードを書いて業務を自動化したい!」という時期は、覚えることが多くて大変ですよね。でも、ここをクリアすればAccess VBAの基本はバッチリですし、あなたの作ったシステムは何倍も軽快に動くようになります。
今回は、Accessのデータベースを操作する上で絶対に避けて通れない「DAO(Data Access Objects)」の心臓部、`CurrentDb`と`DBEngine(0)(0)`の使い分けについて、メモリ管理というプロの視点を交えながら、優しく、そして深く解説していきます。
「毎回なんとなく書いている…」という方は、ぜひここで本質を掴んでいってくださいね!
—
1. Accessデータベースを操作する2つのアプローチ
Access VBAでテーブルのデータを読み書きするとき、私たちは必ず「今開いているデータベースに接続する」という処理を行います。
その接続窓口として、よく目にするのが次の2つです。
1. `CurrentDb` (カレント・データベース)
2. `DBEngine(0)(0)` (ディービーエンジン・ゼロ・ゼロ)
名前の響きからして、`DBEngine(0)(0)`のほうが何やらすごそうな呪文に見えますよね。「どっちを使っても同じなんでしょ?」と思っていませんか?
実はここには、「パフォーマンス」と「メモリ管理」という、Access開発において極めて重要な境界線が引かれているのです。
—
2. 【基礎】それぞれのコードの意味と動き
まずは、それぞれの書き方と裏側の動きを整理してみましょう。
① `CurrentDb` の正体
`CurrentDb`は、現在画面で開いているAccessファイルをオブジェクトとして取得する関数(メソッド)です。
Dim db As DAO.Database
Set db = CurrentDb ‘ データベースへの参照を変数に格納
【ここがポイント】
`CurrentDb`を呼び出すたびに、Accessは「新しいデータベースへの接続(セッション)」を裏側で新しく作成します。そのため、もしループ処理の中で何度も`CurrentDb`を呼び出すと、その都度メモリ消費が増え、最悪の場合はメモリリークや動作の重さを引き起こします。
② `DBEngine(0)(0)` の正体
一方の`DBEngine(0)(0)`は、Accessが起動したときにメモリ上に生成される、メインのデータベースワークスペースの「大本(おおもと)」を直接指し示す表現です。
Dim db As DAO.Database
Set db = DBEngine(0)(0) ‘ 既に開いている大本の接続をそのまま借りる
【ここがポイント】
こちらは新しく接続を作るのではなく、すでに存在しているメインの接続をそのまま使い回す仕組みになっています。そのため、動作が非常に軽量で、メモリの無駄遣いをしません。
—
3. なぜ使い分けが重要なのか?(パフォーマンスとメモリの真実)
「じゃあ、常に速い `DBEngine(0)(0)` を使えばいいのでは?」と思いますよね。
実は、ここが初学者が陥りやすい最大の罠です。
`DBEngine(0)(0)` の隠されたリスク
`DBEngine(0)(0)` はメインの接続を共有するため、大規模なデータ処理や、複雑なトランザクション(一連の処理の途中でエラーが起きたら元に戻す仕組み)を行う際に、Access本体の動作と衝突し、予期せぬエラーやデータ破損のリスクを抱えています。
特に、フォームを開いたまま背後で大量のレコードをゴリゴリ処理するような場面では、`DBEngine(0)(0)` はデリケートすぎて推奨されません。
プロが実践する黄金律:変数に格納した `CurrentDb` の再利用
では、どうすれば安全かつ高速なコードが書けるのでしょうか?
答えはシンプルです。「`CurrentDb` を一度変数に格納し、それを使い回す」 ことです。
これだけで、毎回新しい接続を作る無駄(オーバーヘッド)を回避しつつ、安全性も保つことができます。
—
4. 【実践】大規模データ処理を極限まで高速化するコード例
それでは、数万件のレコードを処理するシーンを想定した、実用的なコードを見てみましょう。
そのまま現場でコピペして参考にしていただけます。
Sub UpdateCustomerData()
‘ 処理の開始時間を記録(パフォーマンス計測用)
Dim startTime As Double
startTime = Timer
‘ 【重要】DAOのオブジェクト変数を宣言
Dim db As DAO.Database
Dim rs As DAO.Recordset
On Error GoTo ErrorHandler
‘ 1. CurrentDbを変数に格納し、接続コストを「1回」に抑える
Set db = CurrentDb
‘ 2. 格納したdb変数を使ってレコードセットを開く
Set rs = db.OpenRecordset(“T_顧客マスタ”, dbOpenDynaset)
‘ レコードが存在するかチェック
If rs.EOF Then
MsgBox “処理対象のデータがありません。”, vbInformation
GoTo Cleanup
End If
‘ 3. 高速なループ処理
rs.MoveFirst
Do Until rs.EOF
‘ 編集モードの開始
rs.Edit
‘ 例:ステータスが「仮登録」のものを「本登録」に書き換える
If rs!Status = “仮登録” Then
rs!Status = “本登録”
rs.Update ‘ 変更を確定
End If
rs.MoveNext
Loop
MsgBox “処理が完了しました。処理時間: ” & Format(Timer – startTime, “0.00”) & “秒”, vbInformation
Cleanup:
‘ 【超重要】メモリ解放(オブジェクトの破棄)
‘ これをサボるとAccessがじわじわとメモリを食いつぶします
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
If Not db Is Nothing Then Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume Cleanup
End Sub
コードの解説とエンジニアの心得
- `Set db = CurrentDb` をループの外で1回だけ実行する
これが最大のポイントです。ループの中で `CurrentDb.OpenRecordset…` と書くのは、ドアを開け閉めしながら荷物を1つずつ運ぶようなもので、非常に非効率です。変数に保持して使い回しましょう。
- 最後の `Cleanup`(メモリ解放)
VBAはプログラムが終了すると自動でメモリを掃除してくれますが、長時間の処理や巨大なデータベースを扱う場合、自分で `Set rs = Nothing` や `Set db = Nothing` と書いてメモリを即座に解放する癖をつけることが、プロへの第一歩です。
—
まとめ:ここをクリアすれば、Access VBAの基本はバッチリ!
今回の内容をギュッとまとめます。
- `CurrentDb`:安全性が高く基本となるが、呼び出すたびに接続が作られるため、変数に格納して使い回すのがベストプラクティス。
- `DBEngine(0)(0)`:非常に軽量だが、メイン接続を共有するためリスクが高く、通常の業務アプリ開発では無理に使わず `CurrentDb` の変数保持で十分なパフォーマンスが出せる。
- 後片付け(`Nothing`):使い終わったオブジェクトはしっかり閉じ、変数に `Nothing` を入れてメモリを綺麗に保つ。
このメモリ管理の意識を持つだけで、あなたが書くAccess VBAのコードは見違えるほど洗練され、エラーの少ない堅牢なシステムに生まれ変わります。
日々の開発、ぜひ楽しんでくださいね!あなたのVBAライフを応援しています。
