【テクニカル・上級編】DAO.RecordsetのFilterプロパティとRecordsetCloneを組み合わせた高速検索エンジン – Access VBA解析バイブル

スポンサーリンク

Accessの「クエリ依存」を脱却せよ:RecordsetCloneとFilterによる高速検索エンジンの極致

Access開発において、多くのエンジニアが陥る罠がある。それは「検索のたびにクエリを書き換え、`Requery`を発行する」という安易なアプローチだ。

ネットワーク負荷、ディスクI/O、そしてJet/ACEエンジンの実行計画再生成。これらはすべて、数千〜数万件のデータセットを扱う現代の業務アプリにおいて、致命的なオーバーヘッドとなる。

真に速いシステムを求めるなら、我々は「メモリ」を支配しなければならない。今回は、`RecordsetClone`と`Filter`プロパティを組み合わせ、メモリ上のレコードセットを自在に操る「インメモリ検索エンジン」のアーキテクチャを解剖する。

1. なぜ「クエリ」ではなく「RecordsetClone」なのか

`Me.RecordsetClone`は、フォームのデータソースのコピーをメモリ上に保持する特殊なDAO.Recordsetオブジェクトだ。これを活用する最大のメリットは、「フォームの表示状態を維持したまま、バックグラウンドで高速なデータ抽出が可能」という点にある。

クエリを動的生成して`RecordSource`に代入すると、フォームのスクロール位置やカレントレコードはリセットされる。これを制御するためのコードを書くのは、愚の骨頂だ。`RecordsetClone`なら、その必要はない。

2. 極限の検索エンジン:実装パターン

以下のコードは、単なるフィルタリングではない。検索対象の絞り込みと、フォームのブックマーク同期を原子操作(アトミック)として実行するプロフェッショナルな実装例だ。

‘ 検索エンジン実行用プロシージャ
Public Sub ExecuteHighSpeedSearch(ByRef frm As Form, ByVal filterString As String)
Dim rs As DAO.Recordset

‘ 1. RecordsetCloneを取得(物理テーブルへのアクセスではない)
Set rs = frm.RecordsetClone

On Error GoTo Cleanup

‘ 2. メモリ上でのフィルタリング適用
‘ ※Filterプロパティはクエリ実行より遥かに高速
rs.Filter = filterString

‘ 3. フィルタ結果が空かどうかの検証
Dim filteredRs As DAO.Recordset
Set filteredRs = rs.OpenRecordset

If filteredRs.EOF Then
MsgBox “対象データは見つかりませんでした。”, vbInformation
Else
‘ 4. ブックマークの同期
‘ メモリ上のカーソルをフォーム側に転送し、表示を即時更新
frm.Bookmark = rs.Bookmark
End If

Cleanup:
‘ オブジェクトの明示的解放は義務
‘ 中途半端な参照はメモリリークの温床となる
If Not filteredRs Is Nothing Then filteredRs.Close: Set filteredRs = Nothing
Set rs = Nothing
End Sub

3. シニアエンジニアが意識すべき「メモリの重み」

この手法を用いる際、避けては通れないのが「オブジェクトのライフサイクル管理」だ。

  • 明示的なCloseとNothing:

DAOオブジェクトはCOMコンポーネントであり、スコープが外れたからといって即座に解放されるとは限らない。特に`OpenRecordset`で生成したサブセットは、必ず`Close`し、`Nothing`を代入してガベージコレクションを待たない姿勢を貫け。

  • Filterの限界値:

`Filter`プロパティは強力だが、非常に複雑な文字列演算や、膨大なレコードセットに対するワイルドカード検索を多用するとパフォーマンスが劣化する。インデックスが貼られたフィールドを検索条件の主軸に据えるのが、アーキテクチャ設計の鉄則だ。

4. レガシー環境でのAPI活用:極限のチューニング

もし、検索の応答性がさらにシビアな環境(数百万レコード規模の統合DBなど)であれば、`Windows API`の`Sleep`や`LockWindowUpdate`を組み合わせ、描画のフリッカーを抑制する小技が効く。

‘ 描画のチラつきを抑えるためのAPI定義(標準モジュールに記述)
Public Declare PtrSafe Function LockWindowUpdate Lib “user32” (ByVal hwndLock As LongPtr) As LongPtr

‘ 呼び出し側
LockWindowUpdate Application.hWndAccessApp
‘ …検索処理…
LockWindowUpdate 0

これを使うことで、フィルタ適用時の画面の再描画を一時的に停止させ、ユーザー体験(UX)を劇的に向上させることが可能だ。

結論:技術は「隠蔽」のためにある

私が開発の現場で最も嫌うのは、「誰が読んでも同じ効率しか出せないコード」だ。

今回の`RecordsetClone`による検索は、Accessの内部挙動を理解している者だけが到達できる、「クエリ再生成という呪縛からの解放」である。複雑なJOIN文をSQLで組み立てる前に、一度立ち止まって考えてほしい。そのデータ、本当にサーバーまで取りに行く必要があるのか?

メモリこそが、戦場における最も強力な武器である。この知見を使いこなし、Accessというレガシーの枠を超えた、高速かつ堅牢なシステムを構築することを期待する。

タイトルとURLをコピーしました