スポンサーリンク

Accessが遅い!はリレーションシップの見直しで解決?劇的パフォーマンス改善テクニック

スポンサーリンク
Access
スポンサーリンク

こんにちは!AccessとVBAを使った業務改善をこよなく愛する、なかぜんです。

「Accessで作ったシステムの動作が、なんだか最近すごく遅い…」
「データが増えるたびに、フォームやレポートを開くのが億劫になる…」
「クエリの実行に時間がかかりすぎて、コーヒーを淹れに行けちゃう…」
上級者の方であっても、こんな悩みを抱えてしまうこと、ありますよね。わかります、その気持ち。

複雑なVBAコードやマシンスペックを疑う前に、ぜひ一度立ち止まって見直してほしい場所があります。それが、テーブル間の「リレーションシップ」です。

データベースの基本であるリレーションシップですが、実はその「貼り方」次第で、パフォーマンスに天と地ほどの差が生まれることがあるんです。この記事では、少し上級者向けの内容になりますが、リレーションシップの考え方を少し変えるだけで、Accessシステムのパフォーマンスを劇的に改善させるテクニックをご紹介します。「正規化」のセオリーから一歩踏み出すことで、驚くほど快適な環境が手に入るかもしれません。ぜひ、最後までお付き合いください!

スポンサーリンク

なぜ、”正しい”リレーションシップが遅さの原因になるのか?

まず、Accessが遅くなる根本的な原因を探ってみましょう。多くの場合、パフォーマンスのボトルネックは、複数のテーブルを結合(JOIN)してデータを取得するクエリにあります。

h3>よくある「正規化された」構成例

例えば、典型的な販売管理システムを考えてみましょう。おそらく、以下のようなテーブル構成になっているはずです。

  • T_受注テーブル: 受注ID, 受注日, 顧客ID, 商品ID, 数量
  • M_顧客マスタ: 顧客ID, 顧客名, 住所, 電話番号
  • M_商品マスタ: 商品ID, 商品名, 単価, カテゴリID

これは、データベース設計の基本である「正規化」に則った、非常に美しい形です。データの重複をなくし、整合性を保つための王道と言えるでしょう。

しかし、例えば「受注一覧フォーム」で「顧客名」と「商品名」を表示したい場合、Accessの内部では何が起こっているでしょうか?

Accessは、受注テーブルの「顧客ID」をキーにして顧客マスタを探しに行き、「商品ID」をキーにして商品マスタを探しに行きます。この「探しに行く」という処理が、まさにテーブルの結合(JOIN)です。データが数千、数万件と増えてくると、この結合処理の負荷がどんどん大きくなり、結果として「遅い…」と感じるようになるのです。

劇的改善テクニック:「戦略的 非正規化」のススメ

そこでおすすめしたいのが、「戦略的 非正規化」というアプローチです。これは、あえて正規化のルールを少しだけ破り、パフォーマンスを優先させる考え方です。

具体例:受注テーブルに「名前」フィールドを追加する

先ほどの例で考えてみましょう。毎回JOINするのが遅いなら、いっそのこと、JOINしなくてもいいようにしてしまえば良いのです。

具体的には、「T_受注テーブル」の構造を次のように変更します。

【変更前】

  • T_受注テーブル: 受注ID, 受注日, 顧客ID, 商品ID, 数量

【変更後】

  • T_受注テーブル: 受注ID, 受注日, 顧客ID, 顧客名, 商品ID, 商品名, 数量

このように、受注テーブルに「顧客名」と「商品名」のフィールドを追加してしまうのです。こうすれば、受注一覧を表示するクエリは、「T_受注テーブル」だけを見に行けばよくなり、JOIN処理が不要になります。これにより、クエリの速度は劇的に向上します。

[Accessのテーブルデザインビューでフィールドを追加しているイメージ]

VBAコードによるデータ自動入力

「でも、それだとデータの整合性が取れなくなるのでは?」

その通りです。素晴らしい指摘ですね。例えば、顧客マスタの顧客名が変更された場合、受注テーブルの名前も更新しないと、データに矛盾が生じます。この問題を解決するのがVBAの役割です。

受注データを入力するフォームで、顧客IDや商品IDが入力(あるいは変更)されたタイミングで、関連するマスタから名前を自動的に取得し、受注テーブルに書き込むコードを仕込みます。

以下は、フォームの「商品ID」コンボボックスの更新後処理イベントに記述するVBAコードの例です。


' --- VBAコード例:商品ID選択時に商品名を自動入力 ---
Private Sub cmb商品ID_AfterUpdate()

    ' Me.cmb商品ID(フォーム上の商品IDコンボボックス)の値がNullなら処理を抜ける
    If IsNull(Me.cmb商品ID.Value) Then
        Me.txt商品名 = Null
        Exit Sub
    End If

    ' DLookup関数を使って、M_商品マスタから商品IDに一致する商品名を取得
    ' 第1引数: 取得したいフィールド名 "商品名"
    ' 第2引数: 探すテーブル/クエリ名 "M_商品マスタ"
    ' 第3引数: 検索条件 "[商品ID] = " & Me.cmb商品ID.Value
    Me.txt商品名 = DLookup("商品名", "M_商品マスタ", "[商品ID] = " & Me.cmb商品ID.Value)

End Sub

【コードの解説】
このコードは、フォーム上で「商品ID」が選択された直後に実行されます。DLookupという便利な関数を使い、「M_商品マスタ」テーブルから、選択された商品IDに合致する「商品名」を瞬時に探し出し、フォームの「txt商品名」テキストボックスに自動でセットします。顧客名についても同様のコードを記述すればOKです。

これにより、ユーザーはIDを選ぶだけで名前が自動入力され、データはそのまま受注テーブルに保存されます。JOINの負荷をVBAの処理で肩代わりさせるイメージですね。

注意点とよくあるミス

このテクニックは強力ですが、いくつか注意点があります。

  • データ更新の徹底: マスタ情報(顧客名など)が変更された場合、関連する過去のトランザクションデータ(受注テーブルなど)も更新する仕組みが必要です。バッチ処理などで一括更新するVBAを用意するなど、運用ルールをしっかり決めておきましょう。
  • 乱用は禁物: 何でもかんでも非正規化すると、逆にデータベースが複雑になり、管理が困難になります。「表示速度が特に求められる画面」や「JOINが多くて遅いクエリ」など、ピンポイントで適用するのが成功の秘訣です。

応用ポイント:インデックスの活用を忘れずに

リレーションの見直しと併せて、絶対に忘れてはならないのが「インデックス」の設定です。

インデックスは、本の「索引」と同じで、特定のデータを高速に探し出すための仕組みです。リレーションシップで利用するキー項目(主キーや外部キー)には、必ずインデックスを設定してください。

インデックスを設定すべきフィールド

  • テーブルを結合するときのキーになるフィールド(顧客ID, 商品IDなど)
  • クエリの抽出条件(WHERE句)で頻繁に使うフィールド
  • 並べ替え(ORDER BY句)でよく使うフィールド

テーブルのデザインビューで該当のフィールドを選択し、フィールドプロパティの「インデックス」を「はい(重複あり)」または「はい(重複なし)」に設定するだけです。これだけでも、パフォーマンスが大きく改善することがよくあります。非正規化と組み合わせることで、相乗効果が期待できますよ。

まとめ:セオリーの先にある快適さを手に入れよう

今回は、Accessのパフォーマンスを劇的に改善するための「戦略的 非正規化」とインデックスの活用について解説しました。

学べたことをおさらいしましょう。

  1. システムのボトルネックは、テーブルのJOIN処理にあることが多い。
  2. 正規化された美しい設計は、参照パフォーマンスの面では不利になることがある。
  3. JOINを減らすために、あえて関連先のデータを自テーブルに保持する「非正規化」が有効。
  4. データの整合性は、VBAのイベント処理などを活用して担保する。
  5. リレーションのキー項目には、必ずインデックスを設定して検索を高速化する。

データベースのセオリーから少しだけ踏み出すのは、勇気がいるかもしれません。しかし、その先にはユーザーがストレスなく使える、快適な業務システムが待っています。

【次のステップ】
まずは、あなたのAccessシステムの中で「一番遅いな」と感じる画面や処理を一つ見つけてみてください。そして、その処理で使われているクエリが、いくつのテーブルをJOINしているか確認してみましょう。もし複数のテーブルをJOINしているなら、今回のテクニックを試す絶好のチャンスです。

小さな改善からで大丈夫です。ぜひ、ご自身のシステムでこの効果を体感してみてくださいね。
あなたのAccessライフが、もっと快適になりますように。それでは、また!なかぜんでした。