【テクニカル・上級編】QueryDefの実行結果をフォームのレコードソースに動的に割り当てる – Access VBA解析バイブル

スポンサーリンク

フォームのレコードソースを極限まで加速させる:QueryDef動的書き換えの深淵

Access開発において、「フォームを開くのが遅い」という嘆きは、多くの場合、不適切なレコードソースのバインドに起因する。`SELECT FROM T_LargeTable`をそのままフォームにぶち込むような実装は、もはや罪に近い。

今回は、`QueryDef`を「使い捨て」または「動的生成」のエンジンとして活用し、実行計画の最適化とフォームの描画速度を極限まで引き上げる手法を伝授する。

1. なぜ「直接SQL」ではなく「QueryDef」なのか

VBAから`Me.RecordSource = “SELECT …”`と記述する手法は簡便だが、Accessのデータベースエンジン(ACE)にとって、それは毎回「未知のクエリ」として扱われる。解析コスト、実行計画の生成コストが毎回発生するのだ。

対して、`QueryDef`オブジェクトを介在させることは、ACEに対して実行計画のキャッシュを促すだけでなく、DAOの強力なパラメータ制御を享受できる。これは単なるコードの整理ではなく、実行時コンパイルのオーバーヘッドを削ぎ落とすためのアーキテクチャである。

2. 実装:QueryDefの動的バインド

フォームの`Open`イベントで、動的にSQLを構成し、それを保存済みクエリ(`qdf_DynamicSource`とする)に流し込む。

‘ フォームのOpenイベントにて
Private Sub Form_Open(Cancel As Integer)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strSQL As String

‘ メモリ最適化:必要な時だけDAOオブジェクトを生成し、即座に破棄する
Set db = CurrentDb
Set qdf = db.QueryDefs(“qdf_DynamicSource”)

‘ SQLの動的構築:インジェクション対策としてパラメータを活用せよ
‘ 複雑な結合やフィルタリングはここで定義する
strSQL = “SELECT FROM T_Data WHERE CategoryID = ” & Me.OpenArgs

‘ SQLの再定義:ACEのキャッシュを更新
qdf.SQL = strSQL

‘ レコードソースの割り当て
‘ この時点でフォームは最適化されたクエリを実行する
Me.RecordSource = “qdf_DynamicSource”

‘ オブジェクトの明示的解放:ガベージコレクションを待つな
Set qdf = Nothing
Set db = Nothing
End Sub

3. レガシー環境を救うメモリ管理の鉄則

AccessのDAOオブジェクトは、明示的に解放しなければメモリリークの温床となる。特に`CurrentDb`を安易にグローバル変数に格納するような設計は、参照カウントを狂わせる元凶だ。

伝説的エンジニアの知見:

  • CurrentDbの再利用を避ける: `CurrentDb`は呼び出すたびに新しいインスタンスを生成する。大規模システムでは、ローカル変数で保持し、処理の最後で確実に `Set … = Nothing` を実行すること。
  • Recordsetのクローズ: `QueryDef`を`Recordset`として開く場合は、`.Close`メソッドの後に`Set … = Nothing`を実行する。これを怠れば、バックエンドのロックファイル(.laccdb)が肥大化し、ネットワークI/Oのボトルネックを招く。

4. APIによる描画抑制という「禁じ手」

もし、クエリの結果を読み込む際の「ちらつき」や「再描画負荷」を極限まで下げたいなら、Windows APIの`LockWindowUpdate`を利用する。これにより、フォームがレコードをバインドしている間の再描画を完全に停止できる。

If VBA7 Then
Private Declare PtrSafe Function LockWindowUpdate Lib “user32” (ByVal hwndLock As LongPtr) As Long
Else
Private Declare Function LockWindowUpdate Lib “user32” (ByVal hwndLock As Long) As Long
End If

‘ 使用例
LockWindowUpdate Me.hWnd
‘ ここでレコードソースの切り替えやフィルタリングを実行
Me.RecordSource = “qdf_DynamicSource”
LockWindowUpdate 0 ‘ 解除することで一気に描画される

5. 最後に:アーキテクトとしての警告

この手法は極めて強力だが、「何でも動的に書き換えれば速くなる」と勘違いしてはならない。

1. クエリの複雑化: 動的SQLが複雑になりすぎると、ACEは適切なインデックスを選択できなくなる。Explain Planを確認し、常に実行効率を監視せよ。
2. 排他制御: 共有フォルダ上のMDB/ACCDB環境では、`QueryDef`の書き換えは排他ロックを誘発する可能性がある。多人数同時接続環境では、`TempVars`やDAOの`CreateQueryDef`(一時的クエリ)の活用を検討すべきだ。

エンジニアリングとは、道具を使いこなすことではない。道具の限界を理解し、その裏側に潜むデータベースエンジンの挙動を制御することだ。貴殿のシステムが、この知見により一瞬で起動するようになることを願う。

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