Access VBAの極意:DAO.RecordsetとFindFirstで「爆速」検索エンジンを構築せよ
こんにちは。現場で泥臭いシステム改修から、数千万レコードを扱う基幹システムのアーキテクチャ設計まで行っているエンジニアです。
今日は、Access VBAを「ただの自動化ツール」から「本格的なデータ処理エンジン」へと進化させるための、最も重要なテクニックの一つ「DAO.Recordsetによる高速検索」についてお話しします。
「マクロの記録」から卒業し、プロのコードを書く第一歩。ここをマスターすれば、あなたのAccessは劇的に軽快になります。
—
1. なぜ「DLookup」ではなく「DAO.Recordset」なのか?
初心者が最初にぶつかる壁、それは`DLookup`関数の多用です。
確かに`DLookup`は便利ですが、あれは「検索のたびにDBへ問い合わせに行く」という非常にコストの高い処理です。100回実行すれば100回、重い扉を叩くようなもの。
一方で、DAO.Recordsetは一度メモリ上にデータをロードし、その中で高速にカーソルを移動させます。特にインデックス(索引)を貼ったフィールドを対象に`FindFirst`メソッドを使うと、Accessはまるで目次を引くかのように一瞬で対象を見つけ出します。
—
2. 実践:FindFirstを使った「爆速」検索エンジンの設計
まずは、最も効率的な検索パターンのコードを見てみましょう。
Public Sub FindRecordOptimized(ByVal targetID As Long)
Dim db As DAO.Database
Dim rs As DAO.Recordset
‘ CurrentDbを直接叩かず、変数に保持することでオーバーヘッドを削減
Set db = CurrentDb
‘ スナップショット形式で開く(読み取り専用ならこれが最速)
Set rs = db.OpenRecordset(“SELECT FROM T_受注管理 WHERE 受注ID = ” & targetID, dbOpenSnapshot)
‘ 検索の開始
With rs
‘ 条件に一致するものを探す(インデックスがある列なら瞬時)
.FindFirst “受注ID = ” & targetID
‘ NoMatchプロパティで判定(ここが重要!)
If .NoMatch Then
Debug.Print “該当するレコードは見つかりませんでした。”
Else
‘ ここで初めてデータにアクセスする
Debug.Print “発見!顧客名: ” & !顧客名
End If
‘ オブジェクトの解放(メモリ管理はプロの基本)
.Close
End With
Set rs = Nothing
Set db = Nothing
End Sub
このコードの「本質」を読み解く
- dbOpenSnapshot: データを書き換えないなら、ロックをかけない「スナップショット」が圧倒的に高速です。
- !顧客名 (フィールド参照): `rs.Fields(“顧客名”).Value`と書くよりも、この「ビックリマーク記法」はコンパイラに優しく、記述もスマートです。
- NoMatchプロパティ: `FindFirst`の後に必ず呼ぶ儀式です。「見つからなかったらどうするか」というエラーハンドリングをここで完結させます。
—
3. 陥りやすい「落とし穴」と回避策
エンジニアとして、皆さんにこれだけは守ってほしい「注意点」があります。
① インデックス(索引)を貼らない罪
`FindFirst`は魔法ではありません。検索対象のフィールドに「インデックス」が貼られていなければ、Accessは全レコードを先頭から順に舐める「フルスキャン」を行います。必ずテーブルのデザインビューで、検索キーとなるフィールドの「インデックス」を「はい(重複なし)」または「はい(重複あり)」に設定してください。 これだけで速度が100倍変わります。
② 明示的なメモリ解放(Close)
DAOオブジェクトは、VBAが終わってもメモリに残り続けることがあります。`rs.Close`と`Set rs = Nothing`を省略するのは、ホテルの部屋を掃除せずに出ていくようなものです。必ずセットで書きましょう。
—
4. ステップアップ:さらに高みを目指すなら
今回紹介した`FindFirst`は、単一のレコードを探すのに最適です。もし、条件に合う複数のレコードを次々に処理したい場合は、`FindNext`をループさせる手法もあります。
しかし、本当に数万件を超えるような複雑な抽出が必要になった時は、`DAO`から一歩進んで「SQLによるパワークエリ」や「ADOによる非同期処理」という選択肢が見えてきます。
まずはこの`FindFirst`と`NoMatch`による「確実な検索」を、あなたのアプリケーションの標準機能として組み込んでみてください。
「なんとなく動く」コードから、「理屈があって速い」コードへ。
この壁を越えたとき、あなたはもう「Accessを使う人」ではなく、「Accessを制御するエンジニア」になっています。
応援しています。何か詰まったら、いつでもまた聞きに来てくださいね。
