【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アプリに「爆速」の翼を与えてあげてください。
何か詰まったら、いつでも聞いてくださいね。応援しています!
