【入門編】DAOのFindFirstでワイルドカード検索を高速化する:Like演算子の罠 – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

「なぜか検索が遅い…」を卒業する。DAO `FindFirst` とインデックスの真実

こんにちは。Access VBAの世界へようこそ。
マクロの記録から一歩踏み出し、自分でコードを書き始めたあなたは、もう立派なプログラマーへの階段を登り始めています。

しかし、開発を進めていくうちに、こんな経験をしたことはありませんか?

「最初はサクサク動いていたのに、データが増えた途端に検索がめちゃくちゃ重くなった……」
「コードは間違っていないはずなのに、なぜか動作がもっさりしている……」

実はこれ、コードの書き方が「間違っている」のではなく、「データベースの仕組み(インデックス)を無視してしまっている」ことが原因かもしれません。

今日は、多くの初学者が陥る、DAOの `FindFirst` メソッドにおける `Like` 演算子の罠、そして「インデックスを殺さない書き方」について、その本質を解き明かしていきましょう。ここをクリアすれば、あなたの作るアプリケーションの品質は一段上のレベルへと跳ね上がりますよ。

1. そもそも `FindFirst` とは何者か?

まずは基本の確認です。DAO(Data Access Objects)を使ってレコードセットを開いたとき、特定の条件に一致する最初のレコードを探し出すのが `FindFirst` メソッドです。

' 基本的な使い方のイメージ
rs.FindFirst "顧客名 = '田中太郎'"

これは非常に強力で便利な道具です。しかし、この「検索条件」の中に `Like` 演算子(ワイルドカード検索)を混ぜたとき、パフォーマンスの地獄が始まることがあります。

2. 「インデックス」という名の魔法の索引

ここで、データベースの高速化の要である「インデックス(索引)」について理解しておきましょう。

想像してみてください。あなたは今、1,000ページある分厚い辞書の中から「Tanaka」という単語を探しています。

  • インデックスがある状態: 辞書の索引(あいうえお順のページ)を見て、「T」のセクションへ一気に飛び、そこから探す。(爆速!)
  • インデックスがない状態: 1ページ目から順番に、全ての単語を読み飛ばしていく。(超絶遅い……)

データベースもこれと同じです。テーブルのフィールドに「インデックス」が設定されていれば、Accessは全データを読み込むことなく、目的のデータへ瞬時にアクセスできます。

3. 【罠】Like演算子の「アスタリスクの位置」が全てを決める

さて、本題です。`Like` 演算子を使ってワイルドカード(`*`)を使うとき、その位置がインデックスを「効かせる」か「殺す」かを決定します。

ここが、エンジニアとしての腕の見せ所です。

❌ パフォーマンスを破壊する書き方(中間一致・後方一致)

' 「〜田中」や「田中〜」など、どこかに田中が含まれるものを探す
rs.FindFirst "顧客名 Like '*田中*'"

この書き方は、データベースから見ると「どこに田中がいるか分からないから、結局1ページ目から全部見なきゃダメだよね」という判断をさせてしまいます。これを専門用語で「フルテーブルスキャン」と呼びます。データが数万件になると、この一瞬の遅延が致命的なストレスになります。

✅ パフォーマンスを最大化する書き方(前方一致)

' 「田中」から始まるものを探す
rs.FindFirst "顧客名 Like '田中*'"

「田中から始まる」という条件であれば、データベースは索引を使って「T」のエリアへジャンプし、そこから「Tanaka…」と続くデータだけを効率よく探し出せます。インデックスが最大限に活用されるのです。

4. 実践:正しいコードの書き方とエラー対策

それでは、実際に現場で使えるコードの形を見てみましょう。
ユーザーが入力した文字を使って検索する、実践的なサンプルです。

Sub OptimizedSearch()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim strSearch As String
    Dim strCriteria As String

    Set db = CurrentDb
    ' 顧客テーブルを開く(顧客名フィールドにはインデックスが設定されている前提)
    Set rs = db.OpenRecordset("tblCustomers", dbOpenDynaset)

    ' ユーザーからの入力(例:田中)
    strSearch = InputBox("検索したい名前の先頭文字を入力してください")

    If strSearch = "" Then Exit Sub

    ' 【重要】前方一致の条件式を作成する
    ' 入力値の前後ではなく、「後ろ」だけにアスタリスクをつけるのがコツ!
    strCriteria = "顧客名 Like '" & strSearch & "*'"

    ' 検索実行
    rs.FindFirst strCriteria

    ' 結果の判定
    If rs.NoMatch Then
        MsgBox "該当するデータは見つかりませんでした。", vbInformation
    Else
        ' 見つかった場合、そのレコードを表示(例として名前を表示)
        MsgBox "見つかりました!: " & rs!顧客名
    End If

    ' 後片付け(これ、忘れるとメモリリークの原因になりますよ!)
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

ここがプロのポイント!

1. `rs.NoMatch` の活用: `FindFirst` は見つからなかったときにエラーを出すのではなく、`NoMatch` プロパティを `True` にします。これを使って、見つからなかった時の処理をスマートに書きましょう。
2. 後片付けの徹底: `Set rs = Nothing`。オブジェクトを使い終わったら解放する。これはAccess VBAにおける「作法」であり、安定したシステムを作るための鉄則です。

5. まとめ:次の一歩へ

最後に、今回の教訓を整理しましょう。

検索パターン 書き方 インデックスの効き方 速度
完全一致 `Name = ‘田中’` 完璧に効く 最速
前方一致 `Name Like ‘田中*’` しっかり効く 高速
中間一致 `Name Like ‘*田中*’` 効かない(死ぬ) 遅い
後方一致 `Name Like ‘*田中’` 効かない(死ぬ) 遅い

「どうしても中間一致で検索したいんだ!」という場面もあるでしょう。その場合は、検索対象のテーブル設計を見直すか、あらかじめ検索用の補助フィールドを作るなどの「設計による解決」が必要になります。

「動けばいい」という段階から、「効率よく動く」という段階へ。
この視点を持つだけで、あなたの書くコードはプロの道具へと進化します。

一歩ずつ、確実に。大丈夫、あなたなら必ず使いこなせるようになりますよ。
また次回のレッスンでお会いしましょう!

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