この記事で分かること
- INDIRECT関数がExcelの動作を著しく重くする「揮発性関数」のメカニズム
- INDEX関数やCHOOSE関数を用いた、動作を軽くするための代替数式の記述方法
- 数式での運用限界を見極め、VBAマクロ化やシステム改修へ移行するための判断基準
INDIRECT関数がExcelを極端に重くする原因と揮発性関数の仕組み
INDIRECT関数は、セルに入力された文字列を介して別のセルを動的に参照できるため、クロス集計や複数シートのデータ抽出に重宝されます。しかし、この関数を多用したブックは、データが増えるほど動作が致命的に遅くなります。その最大の原因は、INDIRECT関数が「揮発性関数(Volatile Function)」と呼ばれる特殊な仕様を持っていることにあります。
通常の関数(非揮発性関数)は、その数式が直接参照しているセルの値が変更されたときにのみ、再計算を実行します。一方で、揮発性関数であるINDIRECT関数は、シート内の「いずれかのセル」の値が書き換わるたびに、変更箇所と直接関係がない場合でも強制的にすべての再計算が行われます。これは、文字列を介した参照先が変更されたかどうかをExcelが事前に検知できないため、整合性を保つために都度計算し直さざるを得ないからです。
例えば、売上データや顧客名簿など、数千行にわたるテーブル内でINDIRECT関数をコピーして配置している場合、1マスのセルの値を更新するだけで数万回以上の不要な再計算処理がバックグラウンドで走ることになります。この累積処理が、Excelを完全にフリーズさせたり、保存やスクロールといった単純な基本操作の速度を著しく低下させたりする直接的な要因です。
INDIRECT関数を使わずに解決する代替設計と数式の書き換え
Excelの処理パフォーマンスを劇的に改善するには、揮発性関数であるINDIRECT関数を、非揮発性関数である他の数式に書き換える「代替設計」が最も効果的です。実務において、特によく使われる代替手法を3つ紹介します。
1. INDEX関数とMATCH関数の組み合わせによる動的参照
行番号や列番号を動的に指定して値を取り出したい場合、INDIRECT関数の代わりにINDEX関数とMATCH関数を組み合わせることで、非揮発性の軽い数式に変更できます。
【INDIRECT関数による重い数式】
=INDIRECT("B" & A1)
【INDEX関数による軽い数式】
=INDEX(B:B, A1)
INDEX関数は、あらかじめ指定したセル範囲内から必要な行・列の値を抽出するため、不要な再計算を発生させません。参照範囲をテーブル化(構造化参照)しておけば、データの追加にも自動で追従します。
2. CHOOSE関数による動的なシート切り替え
「セルに入力したシート名に応じて、参照先を動的に変更したい」という用途は、INDIRECT関数の代表的な使い道です。しかし、シート数がそれほど多くない(目安として10シート未満)場合は、CHOOSE関数とMATCH関数を組み合わせることで、非揮発性での動的参照を実現できます。
【CHOOSE関数を使った代替例】
=CHOOSE(MATCH(A1, {"東日本","西日本","九州"}, 0), 東日本!B5, 西日本!B5, 九州!B5)
この数式では、A1セルに入力された地域名に応じて適切なシートのセルB5を直接参照します。静的な参照リンクを切り替えている扱いになるため、揮発性関数の再計算ループに陥る心配がありません。
3. OFFSET関数との比較および注意点
動的な範囲指定を行う関数としてOFFSET関数もよく知られていますが、OFFSET関数もINDIRECT関数と同様に「揮発性関数」である点に注意が必要です。INDIRECTの代替としてOFFSETを使用しても、再計算による高負荷問題は解消されません。範囲を動的に拡張したい場合は、OFFSETではなく「テーブル機能(構造化参照)」を使用するか、INDEX関数を用いた範囲定義を行ってください。
| 関数名 | 揮発性の有無 | 動作負荷 | 主な用途・代替推奨度 |
|---|---|---|---|
| INDIRECT | あり(揮発性) | 非常に重い | 使用を極力避けるべき |
| OFFSET | あり(揮発性) | 重い | 代替としては不適切。極力避ける |
| INDEX / MATCH | なし(非揮発性) | 非常に軽い | 最適な代替手段として最優先で活用 |
| CHOOSE | なし(非揮発性) | 非常に軽い | 限定的な選択肢(シート切り替え等)に有効 |
INDIRECT関数の多用からVBAマクロ化へ移行すべきかの判断基準
数式の代替設計を行っても、シート数が数十枚に及ぶ場合や、扱うデータ行数が万単位を超える場合には、数式による処理そのものに限界が訪れます。このような局面では、数式を諦めてVBA(マクロ)による処理への移行を判断すべきです。
VBA化を行う最大のメリットは、「処理を実行したいタイミング(ボタン押下時や特定イベント発生時など)にだけ計算を走らせる制御が可能になる」という点です。セルに直接埋め込まれた数式とは異なり、普段の文字入力やセル選択などの日常的な操作中に、都度バックグラウンドで不要な処理が発生することがなくなります。
自社のExcelをVBA化すべきか、そのまま数式設計の調整で耐えるべきかの判断基準を以下に整理しました。
- データ行数が数千件を超え、日々更新される: 数式(特に検索系や動的参照)の計算コストが大きすぎるため、VBAによる一括データ転記処理への移行を強く推奨します。
- 参照先シートが頻繁に増減する: 数式内でシート名を柔軟に管理するのは難しく、複雑なINDIRECT関数のネストを招きやすいため、VBAでシート名をループ処理(For Eachなど)で自動探索させる構造に変えるべきです。
- 数式の作成者以外がメンテナンスを行う: 複雑にネストされたINDIRECT数式は、第三者にとって解読困難なブラックボックスになります。VBAコード内に処理手順のコメントを残し、処理フローを可視化した方が、結果として運用の持続性が高まります。
重いExcelをVBA化して劇的に高速化する具体的な開発手順と注意点
INDIRECT関数の乱用から脱却し、VBAマクロによって動作をサクサク動くように改善するための実践的な開発ステップと、実務での注意点を解説します。
ステップ1:処理ロジックのシンプルな整理
いきなりコードを書き始めるのではなく、まずは「どの条件のときに、どのデータを、どこへ転記するのか」という処理の流れを日本語で設計図としてまとめます。INDIRECT関数で実現していた「動的な参照条件」を、If文やSelect Case文を用いて条件分岐処理として整理します。
ステップ2:高速化を前提としたコーディング手法の適用
VBAを導入しても、記述の仕方によっては処理時間がかえって延びてしまうことがあります。処理速度を最大化するために、マクロの冒頭と末尾に以下の高速化設定を必ず組み込んでください。
Sub ProcessData()
' 画面更新を停止し、再計算を手動に設定して処理を高速化
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' 【ここに主要な転記・集計ロジックを記述する】
' 処理終了後に元の設定に戻す
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
この記述により、処理の途中で1セルずつ値が書き換わるたびに発生する画面描画や、他のすべての関数の自動計算が一時的に停止されます。大量のデータ操作を行う場合でも、体感速度を劇的に向上させることが可能です。
ステップ3:ブラックボックス化の防止と継続的なメンテナンス対策
実務で頻繁に発生するトラブルとして、「重いExcelをVBAで爆速化させたものの、作った担当者が退職してしまい、コードの改修ができなくなってシステムが塩漬けになる」という事例があります。
これを防ぐためには、コード内に徹底して日本語のコメントを入れること、およびプログラムの動きを記載した簡単な業務設計書(マニュアル)をセットで残すルール化が必要です。また、社内リソースだけで複雑なVBAのメンテナンスを続けることが難しい場合は、専門の開発・改修業者に相談し、保守性の高いコードへと最初から最適化して構築してもらう手段も非常に有効です。
INDIRECT関数の見直しに関するよくある質問
数式を書き換えずに、手動再計算に切り替えるだけで運用するのは問題がありますか?
「数式の再計算方法を手動に設定」すれば、確かに日常の入力は軽くなります。しかし、F9キーを押して再計算を行った際に非常に長いフリーズ時間が発生する根本的な問題は解決しません。また、再計算漏れによる数値のズレや、確認ミスの温床になるため、あくまで一時的な応急処置に留め、数式の見直しやVBA化を行うべきです。
INDIRECT関数の代わりとしてINDEX関数を使う際、参照範囲をどう指定すればよいですか?
INDEX関数の第1引数には、参照する可能性のある最大のデータ範囲をあらかじめ直接指定するか、テーブル機能(構造化参照)を使って「Table1[列名]」のように指定します。こうすることで、データが増えた場合にも手動で範囲を修正する必要がなくなり、再計算負荷も極限まで低減されます。
VBAに置き換える場合、どのようなマクロの知識が必要ですか?
セルの値をループ処理する「For Each」や「For Next」構文、指定の条件で分岐させる「If」構文、および「Worksheets(“シート名”).Cells(行, 列).Value」といった基本的なセルの値の読み書きができれば、大半のINDIRECT関数の代替処理は実装できます。