こんにちは!Access VBAの海の荒波にもまれながら、日々の業務自動化に奮闘しているあなたへ。
「マクロの記録」という安全な港を離れ、VBAという大海原に漕ぎ出したあなたなら、きっとこんな壁にぶぶつかったことがあるはずです。
「数万件のデータを扱うと、VBAの処理が途端に遅くなる……。画面がフリーズしたようになって怖い!」
そう、Access(裏で動くデータベースエンジン「ACE/Jet」)は非常に優秀ですが、やり方を一歩間違えると、途端に「おっとり型」に変貌します。特に、VBAの中で一時的なテーブル(ワークテーブル)を作り、そこからデータを検索・突合する処理を素手で行うと、まるで砂漠を歩くような遅さに悩まされることになります。
でも、ご安心ください。ここをクリアすれば、あなたの書くコードは「プロのスピード」に生まれ変わります。
今回は、「DAO.Indexオブジェクト」を使って一時テーブルの検索速度を劇的にブーストさせる極限の知見を、優しく、そして深く伝授しましょう。
—
なぜ、一時テーブルの検索は遅くなるのか?
想像してみてください。
図書館の本棚に、新着の本が「何の整理もされず、ただダンボールに詰め込まれた状態」でドンと置かれているとします。
あなたが「『Access VBAの極意』という本を探して!」と頼まれたらどうでしょう? ダンボール箱を1つずつ、上から順番にひっくり返して探すしかありませんよね。これが、インデックス(索引)がない状態でのテーブル検索です。コンピュータの世界ではこれを「フルテーブルスキャン(全件走査)」と呼びます。
データが100件なら一瞬ですが、10万件になったら……? コンピュータが発狂しそうになりながら、上から順に10万回チェックする羽目になります。
救世主「インデックス(Index)」の正体
ここで登場するのが DAO.Indexオブジェクト です。
あらかじめ「この列(フィールド)の順番で目次を作っておきなさい」とデータベースエンジンに指示を出しておくことで、コンピュータは目次をパッと開いて、目的のデータへ一瞬でたどり着けるようになります。これがインデックスの魔法です。
しかし、ここで一つ重要な事実をお伝えしなければなりません。
「AccessのVBAで `CREATE TABLE` やクエリを使って一時テーブルを作っただけでは、インデックスは自動では貼られない(あるいは主キー以外の複合インデックスなどはコードで指示する必要がある)」ということです。
だからこそ、VBAのコードで自らインデックスを創造してやる必要があるのです。
—
実践!DAO.Indexで検索速度を極限まで高めるVBAコード
百聞は一見にしかず。実際に、一時テーブルを作成し、そこにコードでインデックスをバシッと付与して、爆速でデータを引き当てるプロのコードを見てみましょう。
ご自身のAccessVBAの標準モジュールに、そっと貼り付けてみてください。
Sub BoostSearchWithIndex()
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim idx As DAO.Index
Dim rst As DAO.Recordset
Dim startTime As Double
Set db = CurrentDb
‘ 1. すでに一時テーブルがあれば削除しておく(お掃除は基本です)
On Error Resume Next
db.Execute “DROP TABLE T_TempWork;”, dbFailOnError
On Error GoTo 0
‘ 2. テスト用の一時テーブルを作成する(本来はSELECT INTOなどを想定)
db.Execute “CREATE TABLE T_TempWork (CustomerID Long, CustomerName Text(50), SalesAmount Currency);”, dbFailOnError
‘ 3. 【重要】DAOを使ってテーブル定義オブジェクトを取得する
Set tdf = db.TableDefs(“T_TempWork”)
‘ 4. インデックス(索引)オブジェクトを新しく定義する
Set idx = tdf.CreateIndex(“PK_CustomerID”) ‘ インデックス名は何でもOK
‘ 5. インデックスの対象となるフィールドを追加する
‘ ここがミソ!Fieldsコレクションにフィールド名を追加します
idx.Fields.Append idx.CreateField(“CustomerID”)
‘ 6. 必要に応じてインデックスの特性を設定する
‘ 主キー(Primary)にしたい場合や、重複を許さない(Unique)場合に設定します
‘ idx.Primary = True
‘ idx.Unique = True
‘ 7. テーブルのIndexesコレクションに、いま作ったインデックスを追加!
tdf.Indexes.Append idx
‘ ※インデックスを追加した後は、テーブル定義をリフレッシュするのが鉄則
db.TableDefs.Refresh
‘ — ここから爆速データの検索テスト —
‘ ダミーデータを数件インサートしてみる
db.Execute “INSERT INTO T_TempWork VALUES (1001, ‘株式会社山田商店’, 50000);”, dbFailOnError
db.Execute “INSERT INTO T_TempWork VALUES (1002, ‘鈴木工業’, 120000);”, dbFailOnError
‘ インデックスが効いた状態のテーブルを開く
Set rst = db.OpenRecordset(“T_TempWork”, dbOpenTable)
‘ Indexプロパティに、先ほど作成したインデックス名を指定する!
rst.Index = “PK_CustomerID”
‘ Seekメソッドで、一瞬でデータをピンポイント検索する(社内システムで感動する瞬間です)
‘ Seek “=” の後ろに探したい値を入れる
rst.Seek “=”, 1002
If Not rst.NoMatch Then
MsgBox “見つかりました! 顧客名: ” & rst!CustomerName & ” / 金額: ” & rst!SalesAmount, vbInformation, “爆速検索成功”
Else
MsgBox “データが見つかりませんでした。”, vbExclamation
End If
‘ 後片付け
rst.Close
Set rst = Nothing
Set idx = Nothing
Set tdf = Nothing
Set db = Nothing
MsgBox “処理が完了しました。ここをクリアすれば、Access VBAの基本はバッチリですよ!”, vbInformation
End Sub
—
コードの急所を解説!ここがプロのこだわり
上記のコード、ただ動くだけではありません。Accessのデータベースエンジン(DAO)の挙動を知り尽くしたアーキテクトとしてのこだわりが、いくつか詰まっています。
1. `dbOpenTable` と `Seek` メソッドの組み合わせ
Access VBAでデータを検索するとき、つい `SELECT FROM … WHERE …` というSQLをレコードセットに投げたくなりますよね(`dbOpenDynaset` や `dbOpenSnapshot`)。
しかし、「インデックスを最高速で活かす」なら、テーブルを直接開く `dbOpenTable` と、インデックス専用の瞬間移動メソッド `Seek` のコンビネーションが最強です。
SQLをパースするオーバーヘッドすら削ぎ落とし、ハードウェアの限界に近い速度で目次からデータを引き抜きます。
2. `db.TableDefs.Refresh` のお約束
VBAで `Indexes.Append` を実行した直後、Accessはメモリ上のデータ構造をまだ完全に把握しきれていないことがあります。ここで `db.TableDefs.Refresh` を挟むことで、データベースエンジンに「インデックス構造が更新されたよ!」と確実にお知らせします。これをサボると、次の行で「そんなインデックスねーよ」と怒られる(実行時エラーが起きる)原因になります。
—
陥りやすい罠とエラー回避の知恵
現場でこの手法を使うとき、先輩たちがよくハマる「落とし穴」を先回りして共有しておきますね。
- 罠1: すでに存在するインデックス名を重ねて作ろうとした
- 対策: 同じ名前のインデックスを追加しようとするとエラーになります。一時テーブルを作り直す際は、必ず古いテーブルを `DROP TABLE` で完全に消し去るか、エラーハンドリング(`On Error Resume Next`)で優しくいなす配慮をしましょう。
- 罠2: リンクテーブルに対してインデックスを作ろうとした
- 対策: DAO.Indexによるインデックスの作成・変更は、ローカル(自ファイル内)のテーブルに対してのみ有効です。SQL Serverや別ファイルのAccess(バックエンド)にあるテーブルに対しては、この手法は使えません(リンク元の実体側でインデックスを貼る必要があります)。
—
おわりに
いかがでしたでしょうか?
「なんとなく動くコード」から、「裏側の仕組み(インデックスやデータベースエンジン)を理解して最適化されたコード」へ。この視点を持てた瞬間から、あなたの作るAccessシステムは、見違えるように軽快で頼もしいものに進化します。
「ここをクリアすれば、Access VBAの基本はバッチリですよ!」
さあ、あなたの次の開発現場で、この爆速インデックス技術を試してみてください。きっと、画面の向こうのユーザーから「あれ、今回のシステム、やけに速くない!?」という嬉しい驚きの声が聞こえてくるはずです。
エンジニアとしての誇りと知見を胸に、明日からも最高のコードを書き上げましょう!
