【テクニカル・上級編】【中級】リレーションシップの「参照整合性」をVBAで一時解除・再設定してデータ一括更新を高速化する – Access VBA解析バイブル

スポンサーリンク

参照整合性は「足枷」か「守護神」か。VBAによる動的制御の深淵

Accessにおけるリレーションシップの「参照整合性」。これは小規模なDBでは慈悲深き守護神だが、数万件単位のバルクインポートにおいては、処理速度を劇的に低下させる「最大の足枷」と化す。

インポートのたびに一々リレーションシップを手動で削除し、再作成する……そんな泥臭い運用は、もはやエンジニアの所業ではない。本稿では、DAO(Data Access Objects)を駆使し、リレーションシップをプログラムから動的に操作して、インポート処理のボトルネックを物理的に破壊する方法を伝授する。

1. なぜ「参照整合性」がボトルネックになるのか

参照整合性が有効な状態でレコードを挿入・更新すると、Jet/ACEエンジンは、挿入されるすべてのレコードに対し、外部キー制約のチェックをインメモリまたは一時テーブルで逐次実行する。

これが数万件のバルク処理になると、オーバーヘッドは指数関数的に増大する。物理削除(Drop)を行い、インポート完了後に再作成(Create)するほうが、エンジン側のチェック処理を回避できるため、結果としてトータルコストは大幅に下がるのだ。

2. リレーションシップを解体・再構築するアーキテクチャ

DAOの`Relation`オブジェクトを操作することで、これを実現する。重要なのは、単に削除するだけでなく、「元の定義をどう保持し、どう再構築するか」という設計思想だ。

以下に、実戦投入可能なクリーンなクラス設計の断片を示す。

‘ 参照整合性の動的制御クラス
Option Explicit

Public Sub ToggleRelationship(ByVal strRelName As String, ByVal blnEnable As Boolean)
Dim db As DAO.Database
Dim rel As DAO.Relation

Set db = CurrentDb

If blnEnable Then
‘ リレーションを再構築するロジックをここに
‘ CreateRelation -> CreateField -> Append
Else
‘ リレーションを破壊する
On Error Resume Next
db.Relations.Delete strRelName
On Error GoTo 0
End If

‘ メモリの明示的解放はVBAの作法。放置はメモリリークへの招待状である
Set rel = Nothing
Set db = Nothing
End Sub

3. 【核心】パフォーマンスを極限まで高めるための制約解除ルーチン

単なる削除・作成では不十分だ。インポートの成否がシステムの生死を分ける現場では、以下の点に留意せよ。

1. トランザクションの活用: 削除と再作成の間にインポート処理を挟む場合、必ず`DBEngine.BeginTrans`で囲い、物理的な整合性を保護せよ。
2. インデックスの再考: 参照整合性を外すと検索速度が落ちる場合がある。バルク処理前にインデックスを一時的に無効化し、後で再構築する手法との併用を検討すべきだ。
3. オブジェクトの解放: `CurrentDb`を安易に使い回すな。DAOの`Database`オブジェクトを明示的に作成し、処理が終われば`Close`および`Nothing`を徹底すること。

実践コード:リレーションの再定義

Public Sub RebuildRelationship(strRelName As String, strTable As String, strForeignTable As String)
Dim db As DAO.Database
Dim rel As DAO.Relation
Dim fld As DAO.Field

Set db = CurrentDb

‘ Relationオブジェクトの生成
Set rel = db.CreateRelation(strRelName, strTable, strForeignTable, dbRelationUpdateCascade + dbRelationDeleteCascade)

‘ 外部キー設定(ここが重要)
Set fld = rel.CreateField(“TargetID”)
fld.ForeignName = “ID”
rel.Fields.Append fld

‘ データベースへの適用
db.Relations.Append rel

‘ クリーンアップ
Set fld = Nothing
Set rel = Nothing
Set db = Nothing
End Sub

4. 現場のシニアエンジニアへ贈る「禁じ手」

もし、あなたがレガシーなAccessシステムを保守しているなら、以下の「禁じ手」を心に留めておいてほしい。

  • APIによる排他制御: 非常に大規模なインポートを行う場合、`LockFile`をWindows API(`LockFileEx`等)で直接制御し、他ユーザーからのアクセスを物理的に遮断するレベルの制御が必要になることもある。
  • バックエンドDBの分離: Accessの`.accdb`内で完結させようとするな。データ量が増えるなら、速やかにSQL Server等への移行(アップサイジング)を画策せよ。VBAでリレーションを弄る手法はあくまで「現行アーキテクチャ内での延命措置」であると理解すること。

結論:技術は「制御」のためにある

リレーションシップをVBAで制御することは、データベースの「心臓」にメスを入れるようなものだ。しかし、この制御を手中に収めることで、あなたは「仕様だから遅い」という言い訳から解放される。

システムの本質は、制約をいかに美しく回避し、目的のパフォーマンスを達成するかにある。この記事が、あなたの現場のパフォーマンス改善の一助となれば幸いだ。

諸君、コードに魂を込めたか。最適化に妥協はない。

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