【入門編】DAO.QueryDefの「再利用」がもたらす罠:キャッシュされた実行計画を強制的にリセットするコツ – Access VBA解析バイブル

スポンサーリンク

【Access VBA極意】DAO.QueryDefの「実行計画」を操り、データベースの重さを劇的に解消する技術

こんにちは。Access開発の世界へようこそ。

「最初はサクサク動いていたのに、データ量が増えるにつれて急に遅くなった……」
そんな経験はありませんか?

もしあなたが、`CurrentDb.Execute “UPDATE …” `のように、文字列でSQLを組み立てて毎回投げているなら、少し立ち止まってください。あるいは、`QueryDef`を使ってスマートに書いているつもりでも、実は「古い記憶」に足を引っ張られている可能性があります。

今日は、Access(Jet/ACEエンジン)の心臓部である「実行計画のキャッシュ」を理解し、クエリを常に最速で走らせるための「極限のテクニック」を伝授しましょう。

—

1. なぜAccessは「賢いふり」をして遅くなるのか?

Accessのデータベースエンジンは、一度実行されたクエリの「実行計画(どうやってデータを取得するかという最短ルート)」をメモリ上にキャッシュします。

これは本来、パフォーマンス向上のための機能です。しかし、動的SQL(WHERE句の中身が頻繁に変わるSQL)を`QueryDef`で使い回そうとすると、エンジンは「おっ、前回と同じクエリだな。じゃあ前回のルートを使おう」と勘違いし、新しい条件に対して最適なルートを見失うことがあります。

これが、「なぜか特定の条件でだけ極端に遅い」という現象の正体です。

—

2. QueryDefを「再利用」する時の罠

多くの開発者がやりがちなのが、`QueryDef`のパラメータを更新してそのまま実行する方法です。

‘ よくある実装例(実は落とし穴がある)
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.QueryDefs(“qry_Target”)

qdf.Parameters(“prmDate”) = Me.txtDate
qdf.Execute dbFailOnError ‘ これを繰り返すとキャッシュが古いままになることがある

このコード、小規模なデータなら問題ありません。しかし、データが数万件を超え、インデックスの効き方が条件によって異なる場合、エンジンは「過去の最適解」に固執し、本来の速度を出せなくなるのです。

—

3. 実行計画を「強制リセット」する極意

では、どうすれば良いのか。答えはシンプルです。「使い終わったらキャッシュを捨て、必要なら再構築する」という意志をコードに込めるのです。

以下のコードは、現場で私が実際に使っている「安定と速度を両立させる」ためのテンプレートです。

最強のクエリ実行テンプレート

Public Sub ExecuteOptimizedQuery(ByVal prmValue As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef

Set db = CurrentDb

‘ 1. 一時的にQueryDefオブジェクトを解放し、キャッシュを無効化する
‘ 存在チェックを行い、あれば一度削除してから定義し直すのが「最強の儀式」です
On Error Resume Next
db.QueryDefs.Delete “tmp_DynamicQuery”
On Error GoTo 0

‘ 2. 新たにクエリを生成(毎回クリーンな状態で構築する)
Set qdf = db.CreateQueryDef(“tmp_DynamicQuery”, _
“SELECT FROM T_Sales WHERE SalesDate = [prmDate]”)

‘ 3. パラメータを注入
qdf.Parameters(“prmDate”) = prmValue

‘ 4. 実行
qdf.Execute dbFailOnError

‘ 5. 後始末(ここが重要!メモリから即座に解放する)
qdf.Close
Set qdf = Nothing
Set db = Nothing
End Sub

このコードのポイント

  • Deleteによるキャッシュの強制クリア: `QueryDefs.Delete`を挟むことで、エンジンは「新しいクエリが来た」と認識し、その時の条件に最適な実行計画をゼロから計算し直します。
  • 明示的な解放: `Set qdf = Nothing` を行うことで、Accessのメモリ管理に「もうこのオブジェクトは不要だ」と明示的に伝えます。

—

4. 初心者が陥りやすいエラーと対策

このコードを実装する際、よくあるエラーが「実行時エラー 3012: オブジェクト ‘xxx’ は既に存在します」です。

これは、前回の処理で予期せぬエラーが起き、`Delete`の処理まで辿り着けなかった時に発生します。
これを防ぐために、私のコード例のように `On Error Resume Next` を活用して、「削除しようとして失敗してもスルーする」という堅牢な構造にすることが重要です。

—

最後に:エンジニアとしての心構え

「コードが動くこと」と「コードが速いこと」は別次元の話です。
Access VBAは古い言語だと言われることもありますが、その「実行エンジンのクセ」を深く理解して操ることは、現代のクラウド開発にも通じる非常に高度なスキルです。

今回紹介した「キャッシュのリセット」という視点は、どんなデータベースを扱う際にも必ずあなたの武器になります。

「なぜ遅いんだろう?」と悩んだら、それはデータベースエンジンが「過去の自分」に縛られているサインです。ぜひ今日のコードを試して、あなたのAccessアプリに「爆速」の翼を与えてあげてください。

何か詰まったら、いつでも聞いてくださいね。応援しています!

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