【入門編】DAOの「dbOpenDynaset」と「dbOpenSnapshot」の使い分け:フォームの読み込み速度を劇的に改善する – Access VBA解析バイブル

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

なぜあなたのフォームは重いのか?DAOのカーソルタイプを使いこなして爆速化する極意

「マクロの記録から一歩踏み出して、VBAで本格的なツールを作りたい!」
そう意気込んでコードを書き始めたあなた、素晴らしい一歩です。

しかし、いざ複雑なデータを表示しようとしたとき、こんな経験はありませんか?
「フォームを開くたびに、数秒間マウスカーソルがぐるぐる回って、動作が止まってしまう……」

実はこれ、プログラムの書き方が悪いのではなく、「データの持ち方(カーソルタイプ)」の選択ミスが原因かもしれません。

今日は、Access VBAの心臓部とも言える「DAO(Data Access Objects)」における、2つの魔法の選択肢、`dbOpenDynaset` と `dbOpenSnapshot` の違いについて、その本質を解き明かしていきましょう。ここをクリアすれば、あなたの作るアプリケーションの品質は劇的に向上しますよ。

1. 「動的な映像」か、「静止画」か。

DAOでレコードセット(データの塊)を読み込むとき、私たちは「どういう状態でデータを掴むか」を指示する必要があります。これを「カーソルタイプ」と呼びます。

イメージしやすいように、例え話で説明しましょう。

dbOpenDynaset(ダイナセット):ライブ配信の映像

`dbOpenDynaset` は、いわば「ライブ配信のビデオストリーミング」です。
今、目の前で見ているデータは、常にデータベースの「生の状態」とつながっています。

  • 特徴: 誰かがデータを書き換えたら、すぐに反映される。自分自身でデータを書き換えることもできる。
  • コスト: 常に「最新の状態」を監視し続ける必要があるため、メモリや通信の負荷が少し高い。

dbOpenSnapshot(スナップショット):写真

`dbOpenSnapshot` は、いわば「決まった瞬間の写真」です。
コマンドを実行した瞬間のデータを、パシャリと切り取ってメモリに保存します。

  • 特徴: 一度撮った写真は変わりません。読み込みが非常に高速。ただし、その後に元のデータが変わっても、手元の写真は変わりません。また、基本的には「読み取り専用」です。
  • コスト: 監視の必要がないため、非常に軽量で爆速。
特徴 dbOpenDynaset (ダイナセット) dbOpenSnapshot (スナップショット)
用途 データの入力・編集・更新 データの参照・検索・一覧表示
更新の反映 リアルタイムに反映される 読み込んだ時点のデータで固定
書き込み 可能 基本不可(読み取り専用)
動作速度 普通 圧倒的に速い

2. 実践:フォームの読み込み速度を劇的に変えるコード

では、実際にどのように使い分けるべきか、コードを見てみましょう。
「用途に応じて、最適なカーソルを返してくれる関数」を作るのが、プロの設計です。

''' <summary>
''' 用途に応じて最適なRecordsetを取得する関数
''' </summary>
''' <param name="strSQL">実行するSQL文</param>
''' <param name="isEditMode">編集モードにするかどうか</param>
''' <returns>DAO.Recordset オブジェクト</returns>
Public Function GetSmartRecordset(ByVal strSQL As String, ByVal isEditMode As Boolean) As DAO.Recordset
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim cursorType As Long

    Set db = CurrentDb

    ' --- ここがアーキテクトの判断ポイント ---
    If isEditMode Then
        ' 編集が必要なら、常に最新の状態を追える「ダイナセット」を選択
        cursorType = dbOpenDynaset
    Else
        ' 閲覧のみなら、メモリ負荷が低く爆速な「スナップショット」を選択
        cursorType = dbOpenSnapshot
    End If
    ' ---------------------------------------

    On Error GoTo ErrorHandler

    ' 指定したカーソルタイプでレコードセットを開く
    Set rs = db.OpenRecordset(strSQL, cursorType)
    
    ' 関数に結果をセットして返す
    Set GetSmartRecordset = rs
    Exit Function

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
    Set GetSmartRecordset = Nothing
End Function

''' <summary>
''' フォーム読み込み時のテスト用プロシージャ
''' </summary>
Sub TestLoading()
    Dim rs As DAO.Recordset
    Dim strSql As String
    
    strSql = "SELECT * FROM T_売上データ"

    ' パターンA:一覧表示フォーム(読み取り専用)
    ' スナップショットを使うので、大量データでも一瞬で開く!
    Set rs = GetSmartRecordset(strSql, False)
    Debug.Print "閲覧モードで開きました。"
    
    ' 使い終わったら必ず閉じる(メモリリーク防止の鉄則!)
    rs.Close
    Set rs = Nothing

    ' パターンB:入力フォーム(編集あり)
    ' ダイナセットを使うので、データの更新が可能!
    Set rs = GetSmartRecordset(strSql, True)
    Debug.Print "編集モードで開きました。"
    
    rs.Close
    Set rs = Nothing
End Sub

3. 初心者が陥りやすい「3つの罠」

ここからは、現場でよく見かける「痛いミス」を共有しておきますね。これを知っているだけで、デバッグの時間は半分になります。

罠①:「スナップショットなのに書き込もうとする」

`dbOpenSnapshot` で開いたレコードセットに対して、`.Edit` や `.Update` を実行しようとすると、「操作は許可されていません」というエラーが発生します。
「見るためのデータ」なのか「直すためのデータ」なのか、設計の段階で明確に区別しましょう。

罠②:「Recordsetを閉じ忘れる(メモリリーク)」

これが最も恐ろしい罠です。
`Set rs = db.OpenRecordset(…)` を繰り返しながら、`rs.Close` を忘れると、Accessが確保しているメモリがどんどん膨れ上がり、最終的に「メモリ不足」でクラッシュします。
「開けたら、必ず閉じる」。これはエンジニアの絶対的な規律です。

罠③:「トランザクションの勘違い」

「ダイナセットを使えば、自動的にデータが安全に保存される」と思っていませんか?
ダイナセットはあくまで「データの窓口」です。複数のテーブルをまたぐ複雑な更新を行う場合は、`DBEngine.BeginTrans` を使ったトランザクション処理を組み合わせる必要があります。
(※トランザクションは「全成功か、全失敗か」を保証する仕組みです)

まとめ:次の一歩へ

Access VBAの世界では、「すべてを万能なもの(Dynaset)で済ませようとしないこと」が、プロへの第一歩です。

  • 見るだけなら、Snapshotでスマートに。
  • 直すなら、Dynasetで確実に。

この使い分けができるようになると、あなたの作るアプリは、ユーザーにとって「サクサク動いてストレスのない、最高の道具」に進化します。

「なぜこのコードを書くのか?」という理由を常に意識してみてください。その積み重ねが、あなたを本物のエンジニアへと導いてくれます。

さあ、次は実際にコードを書いて、その速度の違いを体感してみましょう!応援していますよ。

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