「なんとなく」で選ばない。Access VBAの心臓部、DAOの「開き方」でパフォーマンスを支配する
こんにちは。Access VBAの世界へようこそ。
マクロの記録から一歩踏み出し、自分でコードを書き始めたあなたは、すでに「自動化エンジニア」への第一歩を力強く踏み出しています。素晴らしいですね。
さて、コードを書き進めていくと、必ずと言っていいほど遭遇する壁があります。それは「動作が重い」「なぜかエラーが出る」「他の人が使っているときにロックがかかる」といった問題です。
これらは、実はプログラムの書き方以前に、「データの開き方(Recordsetのタイプ)」を間違えていることが原因であるケースが非常に多いのです。
今日は、DAO(Data Access Objects)における二大巨頭、`dbOpenDynaset` と `dbOpenSnapshot` の違いを、アーキテクチャの視点から徹底的に解剖していきます。ここをクリアすれば、あなたの作るシステムは「動くだけのツール」から「プロ仕様のアプリケーション」へと昇華しますよ。
1. イメージで理解する:スナップショットとダイナセット
難しい技術用語の前に、まずは直感的なイメージを持っておきましょう。
`dbOpenSnapshot`(スナップショット)は「写真」
ある瞬間のデータをパシャリと撮影した「写真」をイメージしてください。
写真は眺めることができますが、写真の中の人物の服の色を変えることはできませんよね?
データも同じです。「その瞬間の状態を切り取ったもの」なので、読み取りは爆速ですが、そのデータを使って書き込みを行うことはできません。
`dbOpenDynaset`(ダイナセット)は「ライブ中継」
こちらは、今まさに目の前で起きている出来事を映し出す「ライブ映像」です。
映像の中で誰かが動けば、それもリアルタイムに反映されます。さらに、映像を見ながら「あ、あの人が持っているものをこっちに渡して」と指示(データの更新)を出すことも可能です。
「生きたデータ」に直接アクセスするため、読み書きの両方ができますが、ライブ中継を維持するためのコスト(負荷)がかかります。
2. アーキテクチャの深層:なぜ速度に差が出るのか?
エンジニアとして、一歩踏み込んだ「裏側の動き」を知っておきましょう。ここが、単なるマクロ使いと、設計ができるエンジニアの境界線です。
| 特徴 | `dbOpenSnapshot` (スナップショット) | `dbOpenDynaset` (ダイナセット) |
|---|---|---|
| データの性質 | 静的(読み取り専用) | 動的(更新可能) |
| メモリ消費 | 非常に少ない。データの一時コピーを作るだけだから。 | 比較的多い。常にテーブルとの接続を維持するため。 |
| 処理速度 | 圧倒的に速い。読み取ることに特化している。 | やや遅い。更新のための管理情報が必要だから。 |
| ロックの影響 | 受けにくい。読み取り専用なので、他の操作を邪魔しない。 | 受けやすい。書き込み準備のためにレコードを保持するため。 |
なぜSnapshotは速いのか?
Snapshotは、クエリの結果をメモリ上のバッファにガサッと放り込みます。一度コピーを取ってしまえば、元のテーブルがどう変わろうが関係ありません。そのため、データベースエンジンは「読み取り」だけに全力を注げます。
なぜDynasetは重くなるのか?
Dynasetは、レコードセットの各行が「テーブルのどの位置にあるか」というポインタ(参照情報)を常に保持しています。さらに、あなたがデータを書き換えようとしたとき、即座にテーブルへ反映できるよう、複雑な管理プロセスが裏側で動いています。これが「重さ」の正体です。
3. 実践:使い分けの黄金律
「じゃあ、どっちを使えばいいの?」という疑問にお答えしましょう。結論はシンプルです。
1. 「表示するだけ」「集計するだけ」なら、迷わず `dbOpenSnapshot` を選ぶ。
- レポートの出力、コンボボックスのリスト作成、データの検索表示など。
2. 「値を書き換える」「レコードを追加・削除する」なら、`dbOpenDynaset` を選ぶ。
- 入力フォームでの編集、一括更新処理など。
4. 実装コード:プロの書き方
それでは、実際のコードを見てみましょう。現場でそのまま使える、エラーハンドリング(エラーが起きた時の備え)を組み込んだプロフェッショナルな書き方です。
Option Compare Database
Option Explicit
' =================================================================
' 目的: 用途に合わせたRecordsetの使い分けデモンストレーション
' =================================================================
Sub DemonstrateRecordsetTypes()
Dim db As DAO.Database
Dim rsSnapshot As DAO.Recordset
Dim rsDynaset As DAO.Recordset
Dim strSql As String
' エラーハンドリングの設定
On Error GoTo ErrorHandler
Set db = CurrentDb
strSql = "SELECT EmployeeID, EmployeeName, Salary FROM T_Employees"
' -------------------------------------------------------------
' パターン1: dbOpenSnapshot (読み取り専用・高速)
' 用途: データの表示、計算、レポート作成など
' -------------------------------------------------------------
Debug.Print "--- Snapshot Mode Start ---"
Set rsSnapshot = db.OpenRecordset(strSql, dbOpenSnapshot)
Do Until rsSnapshot.EOF
' 高速に読み取りが可能
Debug.Print "Name: " & rsSnapshot!EmployeeName & " | Salary: " & rsSnapshot!Salary
rsSnapshot.MoveNext
Loop
' ※注意: rsSnapshot!Salary = 500000 などの書き込みはエラーになります
rsSnapshot.Close
Set rsSnapshot = Nothing
Debug.Print "--- Snapshot Mode End ---"
' -------------------------------------------------------------
' パターン2: dbOpenDynaset (更新可能・動的)
' 用途: データの更新、追加、削除など
' -------------------------------------------------------------
Debug.Print "--- Dynaset Mode Start ---"
Set rsDynaset = db.OpenRecordset(strSql, dbOpenDynaset)
Do Until rsDynaset.EOF
' 条件に一致するレコードがあれば、給与をアップさせる
If rsDynaset!Salary < 300000 Then
rsDynaset.Edit ' 編集モード開始
rsDynaset!Salary = 350000 ' 値の書き換え
rsDynaset.Update ' 変更の確定
Debug.Print rsDynaset!EmployeeName & " の給与を更新しました。"
End If
rsDynaset.MoveNext
Loop
rsDynaset.Close
Set rsDynaset = Nothing
Debug.Print "--- Dynaset Mode End ---"
CleanUp:
' 後片付け(オブジェクトの解放はエンジニアの嗜みです)
On Error Resume Next
If Not rsSnapshot Is Nothing Then rsSnapshot.Close: Set rsSnapshot = Nothing
If Not rsDynaset Is Nothing Then rsDynaset.Close: Set rsDynaset = Nothing
If Not db Is Nothing Then Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました。" & vbCrLf & _
"番号: " & Err.Number & vbCrLf & _
"内容: " & Err.Description, vbCritical, "実行エラー"
Resume CleanUp
End Sub
コードのポイント解説
- `On Error GoTo ErrorHandler`: プログラムが予期せぬ事態(データが空だった、ロックされていた等)で止まらないようにするための必須テクニックです。
- `rs.Edit` と `rs.Update`: Dynasetでデータを書き換えるときは、必ず「今から編集しますよ(`Edit`)」と宣言し、「書き換えましたよ(`Update`)」と確定させる必要があります。これを忘れると、データは更新されません。
- `CleanUp` セクション: ここが重要です。エラーが起きても起きなくても、開いたRecordsetを確実に閉じる(`Close`)ことで、メモリリークやデータベースのロックを防ぎます。
5. まとめ:次の一歩へ
いかがでしたでしょうか?
- 速さと軽さを求めるなら `dbOpenSnapshot`
- 書き換えが必要なら `dbOpenDynaset`
この使い分けができるだけで、あなたの作るAccessアプリケーションの安定性とスピードは劇的に向上します。
「マクロの記録」は、あくまで「やりたいことのヒント」です。その裏側で、どのようなオブジェクトが、どのようなモードで動いているのか。その「重み」を感じ取れるようになれば、あなたはもう立派なエンジニアの仲間入りです。
ここをクリアすれば、Access VBAの基本はバッチリですよ。
自信を持って、次のコードを書き進めてくださいね。応援しています!
