【Access VBA極限考察】なぜあなたのコードは遅いのか?『CurrentDb』の呪縛を解く設計論
多くの開発者が、Access VBAでデータベースを操作する際、何の疑いもなく `CurrentDb.Execute` や `CurrentDb.OpenRecordset` を多用します。
「動いているから問題ない」? それは、あなたのコードが「Accessというエンジンの心臓部に無駄な負荷をかけ続けている」事実に気づいていないだけかもしれません。
今回は、業務自動化の現場で「なぜ `CurrentDb` を直接叩いてはいけないのか」というタブーを解き明かし、プロの現場で必須となるDAO.Databaseオブジェクトのキャッシュ戦略を授けます。
—
1. なぜ `CurrentDb` は「悪手」なのか
`CurrentDb` は、呼び出されるたびに新しい `DAO.Database` オブジェクトを生成し、システム内部でセッションの再構築に近い処理を行っています。
もし、1,000件のレコードをループ処理で更新する際、そのループ内で `CurrentDb` を毎回呼び出せば、1,000回のインスタンス生成とメモリ確保のオーバーヘッドが発生します。
- 非効率な構造: インスタンス生成 → リソース確保 → 処理 → 破棄 → (次ループへ)
- 弊害: 処理速度の劇的な低下、メモリリークのリスク、そして何より「データベース接続の不安定化」を招きます。
大規模なデータ処理や、複数のクエリを連続して発行するツールにおいて、この「塵も積もれば山となる」ロスは無視できません。
—
2. プロの設計:DAO.Database変数のキャッシュ化
この問題を解決する唯一の解法は、「モジュールレベル(またはクラスレベル)でデータベース接続を保持し、使い回す」ことです。
一度生成した `CurrentDb` を変数にキャッシュすることで、ループ処理のオーバーヘッドをゼロにし、メモリ消費を最小限に抑えます。
実践:プロダクションレベルのコードテンプレート
以下は、保守性と堅牢性を両立させた設計パターンです。
Option Compare Database
Option Explicit
‘ モジュールレベルで保持するDAO.Database変数
Private m_db As DAO.Database
‘ 初期化処理:データベース接続を一度だけキャッシュする
Private Property Get CurrentDB_Cached() As DAO.Database
If m_db Is Nothing Then
Set m_db = CurrentDb
End If
Set CurrentDB_Cached = m_db
End Property
‘ 終了処理:メモリを確実に解放する
Public Sub TerminateDatabase()
If Not m_db Is Nothing Then
Set m_db = Nothing
End If
End Sub
‘ 【実用例】大量更新処理のデモンストレーション
Public Sub BatchUpdateExample()
Dim rs As DAO.Recordset
Dim db As DAO.Database
‘ キャッシュした接続を取得
Set db = CurrentDB_Cached
‘ トランザクション処理を組み合わせることで更に高速化
db.BeginTrans
On Error GoTo Rollback_Error
Set rs = db.OpenRecordset(“SELECT FROM T_TargetTable”, dbOpenDynaset)
Do Until rs.EOF
rs.Edit
rs!ProcessedDate = Now()
rs.Update
rs.MoveNext
Loop
db.CommitTrans
rs.Close
Set rs = Nothing
Exit Sub
Rollback_Error:
db.Rollback
MsgBox “更新中にエラーが発生しました: ” & Err.Description, vbCritical
End Sub
—
3. 実務で「バグ」を生ませないための3つの鉄則
キャッシュ化を行う上で、必ず守らなければならない「鉄則」があります。
① 常に `Nothing` に戻す(明示的な解放)
Accessの終了時に自動でGC(ガベージコレクション)が働くのを期待してはいけません。特にフォームが閉じられる際や、プロシージャの終了時に `Set m_db = Nothing` を呼び出す習慣をつけてください。
② `BeginTrans` との組み合わせ
キャッシュしたデータベースオブジェクトを使う最大のメリットは、「DAOレベルのトランザクション」を制御しやすくなることです。`db.BeginTrans` を活用すれば、データ整合性を担保しつつ、ディスクI/Oを劇的に削減できます。
③ 外部ファイル接続との使い分け
もし `CurrentDb` 以外の外部mdb/accdbを操作する場合、`DBEngine.OpenDatabase` で取得したオブジェクトを同様にキャッシュしてください。決して「都度接続」を行わないこと。これがプロとアマチュアの決定的な違いです。
—
最後に:エンジニアとしての矜持
「動くコード」を書くのは簡単です。しかし、「負荷を理解し、計算資源を最適化したコード」を書くことこそが、エンジニアの付加価値です。
Access VBAはレガシーな言語だと揶揄されることもあります。しかし、その内部構造を掌握し、メモリとリソースを極限までチューニングしたあなたのツールは、どんな現代的な言語で書かれたコードにも負けない「最強の業務自動化エンジン」となるはずです。
さあ、今すぐあなたのコードにある `CurrentDb` の数を数えてみてください。そこが、あなたのエンジニアとしての進化のスタート地点です。
