Access VBAの深淵:QueryDefを支配し、SQLの実行計画を「意図」せよ
Accessという小さな箱の中で、我々は日々巨大なデータと対峙している。多くのエンジニアは、単にSQL文字列を組み立て、`DoCmd.RunSQL`や`CurrentDb.Execute`に投げるだけで満足しているようだ。だが、それは「動いている」だけであり、「制御している」とは言えない。
真の自動化エンジニアは、QueryDefオブジェクトの裏側にある「実行計画(Execution Plan)」を解像度高く捉えている。今日は、Accessのデータベースエンジン(ACE/Jet)を掌の上で転がすための、極限の技術論を語ろう。
—
1. なぜ「動的SQL」は悪手なのか
多くの初心者は、実行時に`”SELECT FROM T_Orders WHERE UserID = ” & txtID`のように文字列結合でSQLを生成する。これは論理的な怠慢だ。
文字列結合によるSQL生成は、以下の理由でシステムを腐敗させる。
- 実行計画のキャッシュ汚染: SQL文が毎回変わるため、エンジンは実行計画を再構築せざるを得ない。
- プランキャッシュの枯渇: 似たようなクエリが別物として認識され、メモリリソースを無駄に消費する。
- インジェクションの脆弱性: セキュリティの基本原則を放棄している。
解法:QueryDefのパラメータ化
永続的クエリ(QueryDef)にパラメータを定義し、それをVBAから流し込む手法こそが、エンジンの知能を最大限に引き出す唯一の道だ。
‘ QueryDefを用いた最適化されたクエリ実行の模範
Public Sub ExecuteOptimizedQuery(ByVal targetID As Long)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Set db = CurrentDb
Set qdf = db.QueryDefs(“qry_TargetData”) ‘ 事前に定義されたSQL
‘ パラメータを明示的にセット(型安全性の担保)
qdf.Parameters(“p_UserID”).Value = targetID
‘ レコードセットとして取得(Setを実行する前に評価が完了する)
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
‘ …処理…
‘ 明示的解放:VBAのガーベジコレクションを待つな
rs.Close: Set rs = Nothing
qdf.Close: Set qdf = Nothing
Set db = Nothing
End Sub
—
2. インデックスが「死ぬ」瞬間を知れ
SQLがインデックスを無視する理由は、エンジニアの無知にある。以下の「アンチパターン」を即座に排除せよ。
1. 関数のラップ: `WHERE Year(OrderDate) = 2023` は論理エラーだ。`OrderDate`列にインデックスがあっても、全行スキャン(Table Scan)が発生する。`WHERE OrderDate BETWEEN #2023/01/01# AND #2023/12/31#` と書け。
2. 暗黙の型変換: 文字列型の列に対して数値で比較していないか?ACEエンジンは型が一致しない場合、インデックスをバイパスする。
3. ワイルドカードの先頭一致: `LIKE “%ABC”` はインデックスを殺す。`LIKE “ABC%”` ならインデックスを利用できる。
—
3. レガシー環境でのメモリ管理とAPI連携
大規模なシステム連携を行う際、Accessのメモリ管理は極めて繊細だ。特に外部DLL(Windows API)を呼び出す場合、VBAの参照カウンタが正確に管理されていないと、即座にメモリリークを引き起こす。
Windows APIを使ったプロセス制御の極意
大規模なCSVインポートやファイル操作を行う際、`DoEvents`を乱用するエンジニアがいるが、あれはCPUを無駄に回すだけだ。APIで制御せよ。
‘ メモリ解放の鉄則:オブジェクトをNothingにするだけでは不十分な場合がある
‘ 特に外部接続を持つオブジェクトは明示的なCloseが必須
Private Sub SafeResourceCleanup(ByRef obj As Object)
If Not obj Is Nothing Then
On Error Resume Next ‘ 既に閉じている場合のエラーを無視
obj.Close
Set obj = Nothing
On Error GoTo 0
End If
End Sub
—
4. チーフアーキテクトからの提言:クエリの「実行計画」を可視化せよ
AccessにはSQL Serverのような詳細な実行計画ビューアは存在しない。しかし、「ShowPlan」という隠し機能が存在することを知っているか?
`c:\windows\regedit`で`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\16.0\Access Connectivity Engine\Engines\ACE`配下に`ShowPlan`キーを作成し、値を`On`に設定せよ。これを行うと、カレントフォルダに`ShowPlan.out`が出力され、クエリが内部でどのような計算順序で動いているか、その「思考の跡」を覗き見ることができる。
これを見れば、貴方が書いたクエリが「天才のコード」なのか「ゴミの塊」なのか、一瞬で判明するはずだ。
—
結論
Accessは「おもちゃ」ではない。適切に設計され、QueryDefが最適化されたAccessは、中規模の業務システムにおいてはSQL Serverにも引けを取らないパフォーマンスを発揮する。
インデックスを意識し、型を厳格に管理し、オブジェクトのライフサイクルをコントロールせよ。それができれば、貴方はただのVBAユーザーから、真の「業務自動化エンジニア」へと進化する。
コードに魂を込めろ。機械は、書いた通りの結果しか返さないのだから。
