現場の解像度を上げる:DAOとADOの境界線と、メモリアーキテクチャの真実
Access開発において「DAOとADOの使い分け」という命題は、もはや古典的な議論として片付けられがちだ。しかし、真のシニアエンジニアであれば、それが単なる「適材適所」の話ではなく、「Accessのメモリ空間をいかに枯渇させず、かつカーネルレベルのI/O負荷を最小化するか」という、極めて物理層に近い設計思想であることを理解しているはずだ。
本稿では、DAOとADOの使い分けの背後にあるアーキテクチャの深淵に触れ、パフォーマンスを極限まで引き出すための設計指針を提示する。
—
1. 魂の住み分け:なぜDAOが内部で、ADOが外部なのか
結論から言えば、「DAOはAccessデータベースエンジン(ACE)のネイティブな血族であり、ADOは汎用的な傭兵である」という点に尽きる。
- DAO (Data Access Objects): ACEエンジンとのオーバーヘッドがゼロに近い。テーブル構造の直接操作、カレントDB内での高速なレコードセット操作において、ADOはDAOに勝てない。
- ADO (ActiveX Data Objects): OLE DBプロバイダを介するため、外部RDBMS(SQL Server等)との接続性に優れる。非同期処理や、バッチ更新、ストアドプロシージャの実行には不可欠だ。
パフォーマンスの真実
DAOでSQL Serverを操作しようとするのは愚行である。ODBC経由でDAOを介すると、ACEエンジンが一度クエリを解釈し、ODBCドライバに再変換する。この二重の翻訳コストが、ネットワーク越しのレイテンシを増幅させる。逆に、ローカルテーブルをADOで叩くのもまた、COMインターフェースを無駄に跨ぐため、メモリリークの温床となり得る。
—
2. 実装の要諦:オブジェクトライフサイクルの管理
VBAのガーベジコレクションを信じてはならない。特にAccessでは、オブジェクト変数がスコープを抜けても、内部的なキャッシュがメモリを占有し続けることが往々にしてある。
推奨されるDAOによるローカル操作(最速解)
Public Sub ProcessLocalTable()
Dim db As DAO.Database
Dim rs As DAO.Recordset
‘ カレントDBへの参照はCurrentDbを直接叩かず、一度変数に格納する(パフォーマンス向上)
Set db = CurrentDb
Set rs = db.OpenRecordset(“t_TargetTable”, dbOpenTable) ‘ テーブルタイプが最速
With rs
If Not .EOF Then
.MoveFirst
Do Until .EOF
.Edit
!UpdateField = “Processed”
.Update
.MoveNext
Loop
End If
End With
‘ 逆順で明示的に解放
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
推奨されるADOによる外部接続(セキュアかつ堅牢)
外部DBとの接続には、必ず`ConnectionTimeout`と`CommandTimeout`を明示せよ。デフォルト値に頼るエンジニアは、ネットワーク瞬断時にアプリケーションをフリーズさせるリスクを抱えている。
Public Sub ExecuteRemoteSQL(sql As String)
Dim conn As Object ‘ Late Bindingで柔軟性を確保
Dim cmd As Object
Set conn = CreateObject(“ADODB.Connection”)
conn.ConnectionString = “Provider=MSOLEDBSQL;Server=MyServer;Database=MyDB;Trusted_Connection=yes;”
conn.ConnectionTimeout = 15 ‘ タイムアウトを短く設定し、UXを保護
conn.Open
Set cmd = CreateObject(“ADODB.Command”)
With cmd
Set .ActiveConnection = conn
.CommandText = sql
.CommandType = 1 ‘ adCmdText
.Execute
End With
conn.Close
Set cmd = Nothing
Set conn = Nothing
End Sub
—
3. トランザクション処理の極意:ロックの連鎖を断ち切れ
トランザクションを張る際、最も恐ろしいのは「ロックの昇格」によるデッドロックである。
- DAOのトランザクション: `DBEngine.BeginTrans`を使用する。これはセッション全体に影響するため、広範囲を囲いすぎると、他のユーザーがテーブルにアクセスできなくなる。
- ADOのトランザクション: `conn.BeginTrans`を用いる。ADOの場合は、接続を細分化し、必要な最小限のクエリのみをトランザクションブロックに収めることが、高負荷環境での鉄則だ。
—
4. シニアエンジニアへの提言:レガシーとの共存
Access 2016以降、DAOはACEエンジンの一部として最適化され続けているが、一方でADOはWindowsのOS更新により、ドライバの互換性問題(特にSQL Server Native Clientの廃止など)が常に付きまとう。
1. 接続文字列の抽象化: 接続文字列をコードに直書きせず、テーブルまたはINIファイルから読み込む設計にせよ。
2. 型定義の厳格化: `Variant`型は開発の初期段階で排除せよ。メモリ上のアライメントを固定することで、実行速度の向上とデバッグの容易さを手に入れろ。
3. Windows APIの活用: 画面の更新が重い場合は、`LockWindowUpdate` APIを使用して描画を停止せよ。VBAの処理速度そのものよりも、GUIの再描画コストの方が遙かに大きい場合が多い。
結論
DAOとADOの使い分けは、単なる技術選定ではない。システムが扱うデータの「重力」を理解し、メモリとCPUリソースをいかに効率よく調律するかの芸術だ。
あなたが次にAccessを開くとき、そのコードが「動くもの」なのか、それとも「過酷な環境に耐えうるアーキテクチャ」なのか、今一度問いかけてみてほしい。真のエンジニアリングは、常に「最悪のケース」を想定した設計から始まるのだから。
