【実務・中級編】QueryDefの実行計画を強制的に更新する:SQLの実行速度を維持する「統計情報」の意識 – Access VBA解析バイブル

スポンサーリンク

Accessの「クエリが日に日に遅くなる」現象を根絶する:QueryDefの実行計画を強制再構築する極意

Access開発の現場で、ある日突然「以前は一瞬で終わった処理が、なぜか数秒かかるようになった」という相談を受けることはないだろうか。

多くの初心者はこれを「データベースの肥大化」や「インデックス不足」のせいにする。もちろんそれらも要因だが、真の原因は別の場所にある。Access(Jet/ACEエンジン)が保持する「クエリの実行計画(Execution Plan)」の腐敗だ。

今回は、QueryDefを単なる「SQLの保管場所」ではなく、「常に最適化された実行エンジン」として制御するための、プロフェッショナルな設計手法を伝授する。

—

なぜQueryDefは「鮮度」が落ちるのか

Accessのクエリは、初めて実行された際に最適化が行われ、その実行計画がキャッシュされる。しかし、データ量が増減したり、インデックスの統計情報が古くなったりしても、一度生成された計画はすぐには破棄されない。

結果として、エンジンは「過去の最適解」に固執し、現在のデータセットに対しては「最悪の実行ルート」を歩み続ける。これを打破するためには、VBAからQueryDefのプロパティを再定義し、内部的な再コンパイルを強制する設計が必要だ。

堅牢なQueryDef更新・実行の実装パターン

ただSQLを書き換えるだけでは不十分だ。リソースを解放し、明示的にエンジンへ「新しいSQLだ」と認識させる手順を踏む必要がある。

以下に、実務でそのまま利用できる「QueryDef動的更新クラス(またはモジュール)」のコアロジックを提示する。

‘ ———————————————————————-
‘ プロシージャ名:ExecuteOptimizedQuery
‘ 目的:QueryDefの実行計画を強制再構築してSQLを実行する
‘ ———————————————————————-
Public Sub ExecuteOptimizedQuery(queryName As String, newSql As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef

Set db = CurrentDb

‘ 1. QueryDefオブジェクトの取得
‘ 存在しない場合は作成し、存在する場合は参照する
On Error Resume Next
Set qdf = db.QueryDefs(queryName)
If Err.Number <> 0 Then
Set qdf = db.CreateQueryDef(queryName)
End If
On Error GoTo 0

‘ 2. 重要:SQLを入れ替える前に一旦クリアする
‘ これにより、前回の実行計画との依存関係を断ち切る
qdf.SQL = “”

‘ 3. 新しいSQLを代入(ここで再コンパイルがトリガーされる)
qdf.SQL = newSql

‘ 4. パラメータの解決
‘ 必要に応じてここで qdf.Parameters(“…”) = value を設定する

‘ 5. 実行(アクションクエリの場合)
‘ dbFailOnErrorを指定し、実行時エラーを確実にトラップする
qdf.Execute dbFailOnError

‘ 6. クリーンアップ
qdf.Close
Set qdf = Nothing
Set db = Nothing
End Sub

この設計の「プロのこだわり」

1. `qdf.SQL = “”` という儀式

多くのエンジニアは古いSQLの上に新しいSQLを上書きするが、これではエンジンが差分更新を試みてしまい、最適化が不完全になるケースがある。一度空文字を入れることで、エンジンに対し「以前の計画は無効である」という明確なシグナルを送る。これが「再コンパイルの強制」の鍵だ。

2. `dbFailOnError` の徹底

VBAでクエリを実行する際、このオプションを省略してはならない。これがないと、SQLの構文エラーや主キー違反が発生しても黙殺され、後続の処理で不可解なバグを生むことになる。異常系を「即座に検知する」ことは、堅牢なシステムの絶対条件だ。

3. パラメータクエリの活用

今回紹介した手法は、`SELECT FROM TBL WHERE ID = [p1]` のようなパラメータクエリと組み合わせると真価を発揮する。`qdf.Parameters` を通じて値を注入することで、SQLインジェクションを防ぎつつ、実行プランの再利用性を高めることができる。

—

さらにパフォーマンスを突き詰めるには

もし、この手法をとってもなお速度改善が見られない場合は、以下のチェックリストを確認してほしい。

  • 統計情報の更新: バックエンド(リンクテーブルの場合)のデータベースで、統計情報が最新か。SQL Serverがバックエンドなら、`sp_updatestats` を実行するだけで劇的に改善することがある。
  • クエリの複雑性: `QueryDef` の中で別の `QueryDef` を呼び出す「入れ子」をやりすぎていないか。複雑な入れ子は実行計画の予測を極めて困難にする。中間テーブルを作るか、SQLをJOINでフラットに書き直す勇気を持とう。
  • 暗黙の型変換: `WHERE` 句で、インデックスの貼られたフィールドと異なる型で比較していないか(例:数値型フィールドに文字列を渡す)。これはインデックスを無力化し、全件走査(フルテーブルスキャン)を招く最大の敵だ。

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

「コードを書いて動く」のはスタートラインに過ぎない。
「なぜ遅いのか」「なぜこの設計が安全なのか」を論理的に説明し、エンジン(Access)の挙動を支配下に置く。これこそが、ツールを作る担当者から「業務自動化のアーキテクト」へと進化するための境界線だ。

君たちが書くその一行のコードが、現場の時間を何時間削減するか。常にその重みを意識してほしい。

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