Accessの「死」を美しく——一時オブジェクトの墓標とメモリ解放の極意
Access開発において、多くのエンジニアが「機能」を実装することに腐心し、「終焉(クリーンアップ)」を疎かにする。結果、何が起きるか。`.accdb`は肥大化し、断片化によってパフォーマンスは劣化し、不可解な共有違反やロックエラーが現場を蝕む。
特に、一時テーブルや一時クエリを多用する複雑な業務ロジックにおいて、フォームの`Unload`イベントは、単なる「画面を閉じる場所」ではない。それは、システムが健康を維持するための「聖域」である。
本稿では、レガシーを極めたエンジニアの視点から、Accessの寿命を延ばすためのクリーンアップ戦略を伝授する。
—
1. 肥大化の元凶を断つ:CurrentDbの再考
多くの開発者が `CurrentDb.Execute` を乱用するが、`CurrentDb` を呼び出すたびにAccessは内部的に新しいデータベースオブジェクトを生成し、メモリ上にインスタンスを積み上げる。
極限のパフォーマンスを求めるならば、`DAO.Database` 変数をモジュールレベルで保持し、利用する。そして、一時オブジェクトの削除は「保険」ではなく「義務」である。
確実なクリーンアップのための実装パターン
‘ モジュールレベルでのデータベース保持
Private m_db As DAO.Database
Private Sub Form_Load()
‘ 起動時に一度だけ参照を取得
Set m_db = CurrentDb
End Sub
Private Sub Form_Unload(Cancel As Integer)
‘ フォーム終了時に一時オブジェクトを殲滅する
Call CleanupTemporaryObjects
‘ オブジェクトを明示的に解放
Set m_db = Nothing
End Sub
Private Sub CleanupTemporaryObjects()
On Error Resume Next ‘ 存在しない場合のエラーを無視
‘ 一時テーブルの削除
m_db.Execute “DROP TABLE tmp_ImportData”, dbFailOnError
‘ 一時クエリの削除(QueryDefsを走査して削除)
Dim qdf As DAO.QueryDef
For Each qdf In m_db.QueryDefs
If qdf.Name Like “tmp_” Then
m_db.QueryDefs.Delete qdf.Name
End If
Next qdf
‘ 物理的な断片化を防ぐため、DAOのキャッシュをクリア
m_db.TableDefs.Refresh
m_db.QueryDefs.Refresh
End Sub
—
2. なぜ `Unload` なのか:イベントの深淵
初心者は `Close` イベントを使いがちだが、`Unload` こそが唯一の「キャンセル可能な終了処理」である。ここでクリーンアップに失敗すれば、ユーザーは意図せぬゴミを抱えたまま業務を続行することになる。
さらに、Windows APIを駆使して「メモリの強制解放」を試みる手法もあるが、Accessのガベージコレクションは非常に気難しい。私が推奨するのは、APIを呼ぶ前に 「DAOオブジェクトの循環参照を完全に断つこと」 である。
メモリ最適化の極致:明示的解放の鉄則
‘ 複雑なRecordsetを扱う場合、必ず明示的に閉じる
Private Sub SafeCloseRecordset(ByRef rs As DAO.Recordset)
If Not rs Is Nothing Then
rs.Close
Set rs = Nothing
End If
End Sub
このコードを疎かにすると、Accessのメモリ使用量はセッションを跨いで蓄積され、長時間の運用で必ずクラッシュする。メモリは「借りているもの」であり、使い終わったら即座に返却するのがアーキテクトの矜持だ。
—
3. レガシー環境における「最終防衛線」
社内システム統合や外部API連携を行っている場合、一時テーブルは単なるデータ置き場ではなく、システム間の「インターフェース」となる。ここでゴミが残ると、次回の連携処理で致命的な整合性エラーを誘発する。
もし、貴方の管理するシステムが「最近重い」と感じるなら、それはデータ量が増えたからではない。`Unload` 時に死に損なったオブジェクトの残骸が、カタログテーブルを圧迫しているからだ。
伝説的エンジニアからの提言
1. 名前空間の規約化: 一時オブジェクトには必ず `tmp_` 等のプレフィックスを付け、`QueryDefs` 内を正規表現に近いロジックで全探索できる状態を保て。
2. DAOの再利用: `CurrentDb` の安易な呼び出しは禁止。常にデータベース変数を保持せよ。
3. コンパクト修復の自動化: `Unload` イベントの最後に、特定の条件(例:累積処理回数)で `Application.CompactRepair` を走らせるタスクを検討せよ。
結びに:コードは「書く」のではなく「遺す」もの
VBAという言語は、一見すると古臭く、制限だらけに見えるだろう。しかし、その制限の中で、いかにメモリを管理し、いかにリソースを解放するかを突き詰めた先には、OSの深淵を覗くような知的な快感が待っている。
「動けばいい」という言葉は、エンジニアの墓場だ。
終了処理を完璧にこなすこと。それが、次にこのコードを触る誰か、そして何より貴方のシステムに対する最大の敬意である。
さあ、墓標を立てに行こう。貴方のコードが、静かに、そして完璧に終了できるように。
