Excel 揮発性関数 完全ガイド
― 再計算の3種類・INDIRECT問題・条件付き書式の超揮発性・シート間設計・構成変更時の落とし穴まで全網羅 ―

💡 再計算の3種類を理解する

Excelの再計算はすべて同じではありません。以下の3種類を区別することが、パフォーマンス改善の出発点です。

データテーブル
種類 トリガー 再計算範囲 コスト
① Smart Recalc
(依存関係再計算)
セルの値が実際に変わったとき 変更セルに依存する数式だけ 最小・必要な再計算
② 揮発性関数による再計算 ブック内のどこかで何かが変わったとき 揮発性関数を含むセルすべて 揮発性数式の数 × 計算コスト
③ 揮発性アクションによる再計算 特定の操作(フィルタ、名前変更、行挿入等) 影響範囲内の全数式が「dirty」マーク 範囲内の全数式が無条件に再計算
②の重要な性質
揮発性関数を含むセルは毎回再計算されます。しかし、再計算した結果が前回と同じ値なら、そこから先の依存セルは①の判断で「変化なし=再計算不要」となり動きません。揮発性は「そのセルだけ」で止まり、値が変わらなければ先に伝染しないのです。
例で理解する
Z1に =TODAY() を入れ、B1:B1000が =IF(A1<$Z$1,"期限切れ","OK") と参照しているとします。何かのセルを編集すると:
1. Z1(揮発性)が再計算される → 同じ日の作業中は結果が変わらない
2. Z1の値が変わらないため、B1:B1000は再計算されない(Smart Recalc)
3. 日付が変わった翌日の初回再計算ではZ1の値が変わり、B1:B1000も再計算される(正常な依存関係再計算)

【2】核心:「動く列」と「動かない列」を図で理解する

揮発性関数のパフォーマンス問題を理解するうえで最も重要なポイントは、「揮発性数式のセルは毎回動くが、その結果が変わらなければ参照先は動かない」ということです。

シナリオ:関係ないセル(Z1)を編集したとき

Z1 セル(編集した場所)
Z1 に「あ」と入力
← これがトリガー
再計算
開始
A列(INDIRECT入りの数式)
A1 =IF(INDIRECT("元!"&D1)>100,"大","小")
結果:"大"(前回と同じ)
⚡ 再計算された(揮発性だから)
A2 =IF(INDIRECT("元!"&D2)>100,"大","小")
結果:"小"(前回と同じ)
⚡ 再計算された(揮発性だから)
A3 =IF(INDIRECT("元!"&D3)>100,"大","小")
結果:"大"(前回と同じ)
⚡ 再計算された(揮発性だから)
︙ 30,000行すべて再計算 ︙
値が
変わった?
B列(A列を参照する数式)
B1 =A1&":"&C1
💤 再計算しない(A1の値が変わっていないから)
B2 =A2&":"&C2
💤 再計算しない(A2の値が変わっていないから)
B3 =A3&":"&C3
💤 再計算しない(A3の値が変わっていないから)
︙ 30,000行すべてスキップ ︙

処理の流れ(タイムライン)

STEP 1
Z1を編集

再計算サイクル開始
STEP 2
A列の揮発性数式を
全行再計算
(ここでフリーズ)
STEP 3
A列の結果を
前回の値と比較
→ 全行「同じ」
STEP 4
B列は
全行スキップ
(計算しない)
問題の本質はここ
B列は動かない。これは良いことです。しかし STEP 2 でA列の30,000個のINDIRECT数式が毎回再計算されること自体がフリーズの原因です。元データが変わっていなくても、INDIRECTを含むA列は「揮発性だから」というだけで必ず全行が動きます。しかもINDIRECTはシングルスレッドなので、マルチコアCPUでも1コアしか使えません。

INDEX+MATCH に置き換えた場合

Z1 セル(編集した場所)
Z1 に「あ」と入力
← これがトリガー
再計算
開始
A列(INDEX+MATCHの数式)
A1 =IF(INDEX(元!E:E,MATCH(D1,元!A:A,0))>100,"大","小")
💤 再計算しない(非揮発性・参照先に変化なし)
A2, A3 ...
💤 再計算しない
︙ 30,000行すべてスキップ ︙
B列(A列を参照する数式)
B1 =A1&":"&C1
💤 再計算しない
B2, B3 ...
💤 再計算しない
︙ 30,000行すべてスキップ ︙
違いは明白
INDEX+MATCH は非揮発性なので、Z1の編集とは無関係 → A列もB列も一切動かない → フリーズしない。

まとめ:同じ「B列が動かない」でも天と地の差

データテーブル
INDIRECT 方式 INDEX+MATCH 方式
A列 30,000回再計算(結果は同じ) 0回(再計算しない)
B列 0回(A列の値が変わらないため) 0回(同じ)
体感 数秒〜十数秒フリーズ 一瞬で完了
原因 A列の「無駄な再計算」コスト

【3】揮発性関数の一覧

以下はMicrosoft公式ドキュメントおよびCharles Williams(Decision Models / FastExcel)の検証に基づく揮発性関数の一覧です。

データテーブル
関数揮発性リスク・備考
INDIRECT()揮発性シングルスレッド動作・閉じたブック不可・代替推奨
OFFSET()揮発性INDEXで代替可能
TODAY()揮発性1セルに閉じ込めれば影響最小
NOW()揮発性同上
RAND()揮発性毎回値が変わるため依存先も毎回再計算
RANDBETWEEN()揮発性同上
RANDARRAY()揮発性365/2021以降
CELL()揮発性引数によらず揮発性
INFO()揮発性使用頻度は低い
SUMIF()条件付き揮発性第1引数と第3引数のサイズが異なると揮発性(詳細

出典:Microsoft Learn — Excel Improving Calculation PerformanceDecision Models — Volatile Excel Functions

【4】よくある誤解と真実(Myth Busters)

一部のサイトでは以下の関数が「揮発性」と記載されていますが、Microsoft公式ドキュメントとCharles Williamsのテストにより非揮発性が確認されています。

データテーブル
関数実際の揮発性根拠
ROW()非揮発性行挿入時の再計算は依存関係追跡による正常動作
COLUMN()非揮発性同上
ROWS()非揮発性Microsoft Learn で明記
COLUMNS()非揮発性同上
AREAS()非揮発性同上
INDEX()非揮発性OFFSETの代替として推奨される理由
FILTER()非揮発性動的配列関数。ソースデータや条件変更時のみ再計算
XLOOKUP()非揮発性依存関係追跡のみで動作
SumProduct Blog での ROW() の記載について
SumProductの「A to Z of Excel Functions」ではROW()を「volatile」と記載していますが、Microsoft Learnの "Excel Improving Calculation Performance" ではROW / COLUMN / ROWS / COLUMNS / AREAS / INDEXを「previously documented as volatile but are in fact non-volatile」と明記しています。本ガイドでは公式分類に従います。

【5】SUMIF の条件付き揮発性

SUMIF は通常は非揮発性ですが、第1引数(条件範囲)と第3引数(合計範囲)のサイズが異なる場合に揮発性になります。

❌ 揮発性になるケース(サイズ不一致)

=SUMIF(A1:A100, ">0", B1) ← A列100行 vs B列1セル → 揮発性

✅ 非揮発性のケース(サイズ一致)

=SUMIF(A1:A100, ">0", B1:B100) ← 両方100行 → 非揮発性

整形シートでSUMIFを大量に使う場合、範囲サイズを必ず一致させてください。

【6】IF / CHOOSE の揮発性「感染」規則

揮発性かどうかは数式の構文解析(パース)の段階で決まり、実行時の評価とは無関係です。

2段階の処理フロー

データテーブル
段階処理内容揮発性判定への影響
① 構文解析
(Enter時・ブック読込時)
数式テキストに揮発性関数名が含まれるかチェック含まれていればそのセルを「揮発性」としてマーク
② 実行
(再計算時)
数式を実際に計算し分岐を決定影響なし。揮発性かどうかは①で決定済み

具体例

データテーブル
数式揮発性?理由
=IF(1>0, 1, RAND()) 揮発性 RAND()は実行されないが、構文に「RAND」が存在 → 揮発性マーク
=IF(1>0, 1, A1)
(A1に =RAND()
非揮発性 構文には「A1」というアドレスだけ。A1の中身は検査されない
=IF(A1<TODAY(), "期限切れ", "OK") 揮発性 「TODAY」が数式テキストに存在
=IF(A1<$Z$1, "期限切れ", "OK")
(Z1に =TODAY()
非揮発性 数式テキストに揮発性関数名なし。$Z$1はただのアドレス
セル参照が揮発性を「感染」させない理由
構文解析では $Z$1 は「アドレス」として処理されるだけで、Z1の中身を見に行きません。これが「1セルに閉じ込める」パターンの根拠です。
AND / OR に注意
AND()OR() はIFと異なり、すべての引数を常に評価します。=AND(TRUE, RAND()>0.5) は揮発性であるだけでなく、条件に関わらず毎回 RAND() が実行されます。IFの「短絡評価(条件に応じて片方だけ実行)」とは異なるため注意が必要です。

【7】揮発性関数を「1セルに閉じ込める」パターン

シナリオ:1000行の日付列で期限切れかどうかを判定したい

❌ 悪い例:1000行すべてに TODAY() を直接書く

B1 =IF(A1<TODAY(),"期限切れ","OK") ← 構文にTODAYがある → 揮発性 B2 =IF(A2<TODAY(),"期限切れ","OK") ... B1000 =IF(A1000<TODAY(),"期限切れ","OK") → 1000個のセルすべてが揮発性 → 毎回1000回 TODAY() が再計算される

✅ 良い例:TODAY() は Z1 に1つだけ。他は Z1 を参照

Z1 に入れる数式

=TODAY()

B1:B1000 に入れる数式(非揮発性)

=IF(A1<$Z$1,"期限切れ","OK")
→ 揮発性数式はZ1の1つだけ → 同じ日の作業中はZ1の値が変わらないのでB列も動かない
なぜ B1:B1000 は非揮発性なのか?
前セクションで説明した構文解析の規則のとおり、$Z$1 はただのセル参照であり、Excelは Z1 の中身を見に行きません。数式テキスト IF(A1<$Z$1,"期限切れ","OK") に揮発性関数名が含まれないため、非揮発性と判定されます。

【8】名前の管理(Name Manager)と揮発性

トラップ①:名前の定義に揮発性関数を入れる

名前の管理で 今日 = TODAY() のような定義を作ると、その名前を参照するすべての数式が揮発性になります。しかも名前が使われるたびに評価されるため、100箇所で「今日」を参照すると100回 TODAY() が実行されます。

❌ 名前の管理に揮発性関数を直接定義

名前の管理: 今日 = TODAY() A1 =IF(B1<今日,"期限切れ","OK") ← 名前展開で TODAY() が埋め込まれる → 揮発性 → 100箇所で「今日」を使うと、TODAY() が100回評価される

✅ セルに書いて名前はセル参照に

Z1 に入れる数式

=TODAY()
名前の管理: 今日 = Sheet1!$Z$1 A1 =IF(B1<今日,"期限切れ","OK") ← 名前はセル参照に解決 → 非揮発性 → TODAY() の評価は Z1 の1回だけ

トラップ②:名前の操作自体が揮発性アクション

名前の管理で名前を追加・変更・削除する行為自体が「揮発性アクション」です。参照先が単純なセル範囲(例: =Sheet1!$A$1:$D$50)であっても、名前を操作するだけでブック全体の再計算がトリガーされます。大量の名前を一括整理する際にExcelがフリーズする原因はこれです。

設計指針
揮発性関数を名前の定義に直接入れない。揮発性関数は必ず1つのセルに書き、名前にはそのセル参照を設定する。

【9】INDIRECT の3つの問題点

データテーブル
#問題説明
1常に揮発性引数や結果に関係なく、すべての再計算サイクルで再評価される。結果が前回と同じでも計算自体は毎回走る
2閉じたブック参照不可参照先のブックが閉じているとエラー。INDEX/MATCHは閉じたブックでも動作する
3シングルスレッド動作Excelのマルチスレッド再計算を無効化し、1つのCPUコアでしか計算されない。数万行で致命的なボトルネック
代替手段を検討してください
シート切替 → CHOOSE() または XLOOKUP()、動的範囲 → INDEX() のコロン構文、カスケードドロップダウン → FILTER()(365/2021以降)

【10】揮発性アクション一覧

以下の操作は揮発性関数とは無関係に、影響範囲内のすべての数式を「dirty(要再計算)」としてマークします。これが③の再計算です。

データテーブル
操作影響範囲備考
行・列・セルの挿入/削除/移動名前付き範囲やクロスシート参照を含む場合、ブック全体構造変更は参照を再構築するため
名前の管理で名前を追加/変更/削除ブック全体参照先が単純なセル範囲であっても操作自体がトリガー
シート名変更・シート移動・シート削除該当シートを参照する全数式参照文字列の更新が必要なため
オートフィルタ操作フィルタ範囲内の全数式フィルタ切替のたびに範囲内が全てdirty
行/列境界線のダブルクリック(自動調整)自動計算モード時にブック全体画面再描画を伴う
CSVファイルを開く手動計算モードでもブック全体Excel仕様の例外的動作
ゴールシーク反復ごとにブック全体収束するまで繰り返される
行の非表示/再表示(Excel 2003のみ)ブック全体2003限定のレガシー動作。2007以降は発生しない

【11】ブック構成の変更と揮発性アクションの連鎖 ― 数万行で起きる地獄

ブックの構造を変更する操作(シート名変更、シート移動、行列の挿入削除、名前の一括整理など)はすべて揮発性アクションです。数万行の数式が入ったブックでこれらを実行すると、構成変更のたびにブック全体が再計算され、深刻なフリーズが発生します。

具体的に何が起きるか

シナリオ:整形シートに30,000行の数式があるブックで、シート名を「元データ」→「原本」に変更する

STEP 1
シート名を
「元データ」→「原本」
に変更
STEP 2
「元データ」を参照する
全数式の参照文字列
が「原本」に更新される
STEP 3
揮発性アクション発動
影響範囲の全数式
dirtyマーク
STEP 4
30,000行すべてが
再計算される
(フリーズ)

さらに悪いことに、この30,000行にINDIRECTやOFFSETが含まれている場合、通常の揮発性再計算(②)に加えて揮発性アクション(③)のdirtyマークが重なり、二重に再計算が走ります。

特に危険な操作パターン

データテーブル
操作影響対策
シート名の変更 該当シートを参照する全数式が再計算 シート名は最初に確定させ、後から変えない
行の大量挿入/削除 名前付き範囲やクロスシート参照がある場合、ブック全体 構造変更前に手動計算モードに切替。完了後にCtrl+Alt+F9で一括再計算
名前の一括削除/整理 1つ削除するたびにブック全体が再計算 手動計算モードで一括処理。またはVBAで Application.Calculation = xlManual にしてから実行
シートの移動/削除 参照先を含む全数式 シート構成は初期段階で確定させる
オートフィルタの切替 フィルタ範囲内の全数式 INDEX+MATCH / FILTERで別シートに抽出し、元データにはフィルタを使わない
実務での教訓
「数万行の数式が入ったブックを後から構成変更するのは地獄」。シート名、シート構成、名前の定義は最初の設計段階で確定させてください。後から変更すると、変更のたびに数万行が再計算されてExcelがフリーズします。どうしても変更が必要な場合は、必ず手動計算モードに切り替えてから行ってください。

【12】条件付き書式:「超揮発性」 超揮発性

条件付き書式の数式は画面の再描画(repaint)のたびに評価されます。揮発性関数よりさらに強力です。

データテーブル
操作通常の揮発性関数条件付き書式の数式
セルの値を変更再計算される再評価される
スクロール再計算されない画面に入った行が再評価
シート切替(戻る)再計算されない表示領域が再評価
ウィンドウ復元再計算されない表示領域が再評価
手動計算モード抑制できる抑制できない
印刷プレビュー / PDF出力再計算されない全行が一括評価 → フリーズ

再計算範囲は「画面に表示されている部分」だけ

通常のスクロール操作では、条件付き書式の再評価は画面に新しく表示された行だけで発生します(1画面30行なら30行分)。画面外の行は評価されません。

ただし、以下のケースでは全行が一括評価されます:

全行が一括評価される危険な操作
印刷プレビュー — 全ページを描画しようとするため、全1万行の条件付き書式が一気に評価 → 数十秒フリーズ
PDF出力 — 同上
Ctrl+End → 先頭へ戻る — 最終行までジャンプした際に大量の行が描画対象に
ページレイアウトビュー — 全ページの描画が発生

起きること(具体的な症状)

1万行に =AND($D1>TODAY(), $E1="") のような条件付き書式を設定した場合:スクロールするたびに画面に入った行の数式が全て評価されます(1画面30行なら30回)。TODAY()は揮発性なのでさらに重くなります。手動計算モードにしても条件付き書式の評価は止められません。上下にスクロールを繰り返すだけでExcelが目に見えてカクつきます。印刷プレビューを表示すると、全1万行を一気に描画しようとして数十秒フリーズすることもあります。

対策:補助列を使う

❌ 条件付き書式にTODAY()を直接書く

条件付き書式の数式: =AND($D1>TODAY(), $E1="") → 描画のたびに TODAY() を含む数式が評価される

✅ 補助列で計算し、条件付き書式は値比較のみ

Z1 に入れる数式

=TODAY()

補助列 F1 に入れる数式

=IF(AND(D1>$Z$1, E1=""), 1, 0)

条件付き書式の数式(単純な値比較 → 高速)

=$F1=1
→ 条件付き書式は単純な値比較だけ(高速) → TODAY() の評価は Z1 の1回だけ → F列の再計算は Smart Recalc で必要なときだけ
条件付き書式の範囲を限定する
条件付き書式を設定する範囲は必要最小限にしてください。A1:J10000 に設定するよりも、実際にデータがある範囲だけに限定する方が描画時の評価回数が減ります。使わなくなった条件付き書式は必ず削除してください。

【13】シート間の依存関係と揮発性の影響

元データ
手入力 / 外部取込
整形シート
数万行の数式
出力シート
XLOOKUPで表示・印刷

整形シートが再計算される条件

データテーブル
#条件再計算の種類
1元データの参照先セルが実際に変更された① Smart Recalc(正常・必要な再計算)
2整形シート自体に揮発性関数がある② 揮発性関数による再計算
3整形シートに揮発性アクション(フィルタ操作・行挿入・シート名変更等)が行われた③ 揮発性アクション

出力シートで操作しても、整形シートの元データが変わっていなければ、整形シートの数式は動きません(条件2と3に該当しない限り)。出力シートにある揮発性関数は出力シートだけで再計算され、その結果が変わらなければ整形シートには一切波及しません。

整形シートの状態別:影響の比較

データテーブル
整形シートの状態 再計算回数 コスト 出力シートへの連鎖
揮発性関数なし 0 ゼロ 元データが変わらない限りなし
TODAY() が1セルだけ 1 ほぼゼロ 同じ日なら値が変わらないためなし
OFFSET が100個 100 中程度 結果が同じならなし(ただし100回の計算コストは発生)
INDIRECT が数千〜数万個 数千〜数万 非常に重い 結果が同じでも計算自体でフリーズ

判定フローチャート

整形シートに揮発性関数がありますか? ├─ No → ✅ 安全。元データが変わらない限り整形シートは動かない └─ Yes → 揮発性数式はいくつ? ├─ 少数(1〜数個) → 注意 コストほぼゼロ。許容範囲 │ (TODAY 1個、CELL("filename") 1個 等) └─ 多数(数百〜数万) → 要改善! INDEX+MATCH / XLOOKUP / FILTER に置換

危険シナリオ:印刷・PDF出力時の連鎖

出力シートを印刷・PDF出力する際に最も深刻な遅延が発生します:


出力シートに
揮発性関数
→ 再計算

出力シートに
条件付き書式
全行評価
(超揮発性)

整形シートに
揮発性関数が数千個
全て再計算

③の結果が
変わった場合
→ 出力シートも
再度再計算

このような連鎖が発生するため、整形シートから揮発性関数を排除することが最も効果的な対策です。

対策の鉄則
整形シートは揮発性フリーに設計する。XLOOKUP / INDEX+MATCH 等の非揮発性関数だけで構成する。TODAY()はシートごと1セルに閉じ込め、他はそのセル参照。条件付き書式は最小限にし、補助列で判定させる。

【14】オートフィルタ vs 関数による抽出

オートフィルタはフィルタを切り替えるたびにフィルタ範囲内の全数式が dirty としてマークされます(③揮発性アクション)。INDEX+MATCH や FILTER関数で別シートに抽出する方式は、①のSmart Recalcだけで動作します。

データテーブル
比較項目 オートフィルタ INDEX+MATCH FILTER関数
再計算の種類③ 揮発性アクション① Smart Recalc① Smart Recalc
影響範囲フィルタ範囲内の全数式条件に依存するセルだけFILTER数式と依存先だけ
元データへの影響元データの数式もdirtyに影響なし影響なし
関数の揮発性非揮発性非揮発性
対応バージョン全バージョン全バージョン365 / 2021 / 2024
条件セルを変えたときの再計算は「正常な依存関係再計算」
INDEX+MATCHやFILTERで抽出した結果が条件セルの変更に応じて更新されるのは①のSmart Recalcです。これはExcelの正常な動作であり、③の「不要な全範囲dirty」とは根本的に異なります。

【15】INDEX+MATCH と FILTER関数の違い

どちらも非揮発性ですが、動作の仕組みが異なります。

INDEX+MATCH:1行1数式

=INDEX(元データ!A:A, MATCH(H$1, 元データ!C:C, 0))

MATCHが最初の一致行番号を返し、INDEXがその行の値を取得。複数行を抽出するにはSMALL+IF等の追加工夫が必要。行ごとに1つの数式が必要。

FILTER関数:1数式でスピル

=FILTER(元データ!A:E, 元データ!C:C=H1, "該当なし")

条件に一致する全行が1つの数式から自動展開(スピル)。複数条件は * (AND) や + (OR) で組み合わせ。結果の行数が動的に変化。

データテーブル
比較項目INDEX+MATCHFILTER関数
揮発性非揮発性非揮発性
数式の数抽出行数ぶん(多い)1つ(スピルで展開)
複数条件SMALL+IF等で複雑配列演算で簡潔
結果行数固定(事前に枠を用意)動的(自動拡縮)
対応バージョン全バージョン(Excel 97以降)Microsoft 365 / Excel 2021 / Excel 2024
再計算コスト数式数ぶんの計算1数式で一括計算(大量データでは効率的)
FILTER関数の対応バージョンについて
FILTER関数は Microsoft 365Excel 2021(コンシューマー版)、Excel 2024(コンシューマー版)で使用できます。ただし企業向けの Office LTSC 2021 / LTSC 2024(ボリュームライセンス版)ではエディションによって利用できないケースがRedditやMicrosoft Q&Aで報告されています。利用可否は ファイル → アカウント でExcelのバージョン情報を確認してください。Excel 2019以前では使用できないため、INDEX+MATCHが唯一の選択肢です。

【16】数万行のINDIRECT問題:「結果が変わらなくても動く」コスト

「便利だから」とINDIRECTやOFFSETを数万行に使ってしまうケースは、パフォーマンス上の最大の落とし穴です。

何が起きるのか(図解)

A列:INDIRECT × 30,000行
A1 =INDIRECT("元!"&D1)
結果:150(前回と同じ)
⚡ 再計算された
A2 =INDIRECT("元!"&D2)
結果:80(前回と同じ)
⚡ 再計算された
︙ 30,000行すべて再計算 ︙
シングルスレッドで数秒〜十数秒
値が
変わった?
No
B列:A列を参照 × 30,000行
B1 =A1*1.1
💤 スキップ
B2 =A2*1.1
💤 スキップ
︙ 30,000行すべてスキップ ︙
A列の値が変わっていないから

INDIRECTの結果が変わらない場合の詳細

元データが一切変更されていない場合、30,000個のINDIRECTは全て再計算されますが、結果の値は前回と同じです。この場合:

データテーブル
状況A列(INDIRECT)の再計算B列(A列参照)の再計算
元データ変更なし 30,000回すべて再計算(値は変わらない) 0回(値が変わらないためSmart Recalcでスキップ)
元データ1セル変更 30,000回すべて再計算(1つだけ値が変わる) 変わった1セルに依存するB列の数式だけ
元データ大量変更 30,000回すべて再計算 変わったセルに依存するB列の数式すべて

つまり、依存先への連鎖は起きませんが、INDIRECT数式自体の30,000回の再計算コストが問題なのです。しかもINDIRECTはシングルスレッドなので、マルチコアCPUでも1コアしか使えず、計算が直列で走ります。

INDEX+MATCH / FILTER に置き換えた場合の比較

データテーブル
方式元データ変更なし時マルチスレッド体感
INDIRECT × 30,000 30,000回 不可(シングルスレッド) 数秒〜十数秒フリーズ
INDEX+MATCH × 30,000 0回 可能 一瞬
FILTER × 1(スピル) 0回 可能 一瞬
結論
「結果が変わらなければB列は動かない」は事実。しかし問題はA列のINDIRECT自体が毎回30,000回も再計算されるコスト。30,000個のINDIRECTがシングルスレッドで毎回再計算されることで、データが変わっていないにもかかわらず数秒〜十数秒のフリーズが発生します。INDEX+MATCHやFILTERに置き換えれば、この無駄な再計算はゼロになります。

【17】揮発性関数の正しい使いどころ

揮発性関数は「悪」ではありません。適切な場面で使えば便利で、問題は使い方です。重要なのは「数」と「場所」のコントロールです。

適切なケース

データテーブル
ケース関数理由
ダッシュボードの日付表示(1セル)TODAY()1セルだけなのでコストほぼゼロ
乱数によるシミュレーションRAND()毎回変わることが目的。使い終わったら値で貼り付け
ファイルパスの取得(1セル)CELL("filename")コスト軽微
少数のシート動的参照INDIRECT()数個なら影響は限定的。数百以上ならCHOOSE/XLOOKUPに置換

避けるべきケース

データテーブル
ケース問題の関数代替手段
数千〜数万行のデータ整形INDIRECT / OFFSETINDEX+MATCH / XLOOKUP / FILTER
条件付き書式の数式TODAY()補助列で計算、書式は値比較のみ
全行に同じ日付比較TODAY() を全行にZ1に1つだけ、他は $Z$1 参照
名前の管理の定義式揮発性関数を直接記述セルに書いて名前はセル参照に

判断基準:使用数 × 依存の深さ

使用数が少ない 使用数が多い ┌──────────────┬──────────────┐ 依存が │ ✅ 許容 │ 注意 要検討 │ 浅い │ TODAY 1個 │ OFFSET 200個 │ ├──────────────┼──────────────┤ 依存が │ 注意 要検討 │ 要改善! │ 深い │ INDIRECT 5個 │ INDIRECT │ │ →他シート参照 │ 30,000個 │ └──────────────┴──────────────┘
過剰な回避にも注意
揮発性関数を避けるためにCHOOSEで数十のシート名を手書きしたり、OFFSETの代替で非常に複雑なINDEX式を書いたりすると保守性が低下します。「数個の揮発性関数」と「著しく複雑な非揮発性数式」の間では、コストと保守性のバランスを考えてください。

【18】脱・揮発性!代替手段一覧

データテーブル
目的揮発性の方法非揮発性の代替
動的範囲の取得 =OFFSET(A1,0,0,COUNTA(A:A),1) =A1:INDEX(A:A,COUNTA(A:A))
(INDEXのコロン構文)
シートの動的切替 =INDIRECT("'"&B1&"'!A1") =CHOOSE(C1, Sheet1!A1, Sheet2!A1, Sheet3!A1)
またはテーブル+XLOOKUP
カスケードドロップダウン =INDIRECT(D1)(名前参照) =FILTER(品目一覧, カテゴリ列=D1)
(365/2021以降)
今日の日付との比較 各行に TODAY() Z1に =TODAY()、各行は $Z$1 参照
データの抽出・フィルタリング オートフィルタ(揮発性アクション) INDEX+MATCH / FILTER で別シートに抽出

📝 まとめチェックリスト

データテーブル
#チェック項目
1再計算は3種類:① Smart Recalc、② 揮発性関数、③ 揮発性アクション。②と③を最小化する
2揮発性関数は「そのセル」が毎回動く。しかし結果が変わらなければ依存先は動かない
3問題は「依存先への連鎖」ではなく「揮発性数式自体の計算コスト × 数」。INDIRECTはシングルスレッド
4IF / CHOOSEの揮発性は構文解析レベル。セル参照は揮発性を「感染」させない。AND/ORは全引数を常に評価する
5TODAY / NOW は1セルに閉じ込め、名前の管理にも直接書かない(名前は使用箇所ごとに再評価される)
6ROW / COLUMN / ROWS / COLUMNS / INDEX / FILTER は非揮発性。安心して大量に使える
7SUMIFは範囲サイズを一致させる(不一致で揮発性化)
8条件付き書式は「超揮発性」。手動計算モードでも止まらない。画面表示部分だけ再評価だが、印刷プレビューでは全行一括評価。補助列を活用
9オートフィルタは揮発性アクション。INDEX+MATCH / FILTERによる別シート抽出が高速
10名前の追加/変更/削除は揮発性アクション。一括操作時はフリーズ注意
11ブック構成の変更(シート名変更・行列挿入削除・シート移動削除)は揮発性アクション。数万行のブックでは必ず手動計算モードで実行する
12整形シートは揮発性フリーに設計する。数万行のINDIRECTはデータが変わらなくても毎回フリーズ。出力シートとの連鎖にも注意
13揮発性関数は「悪」ではない。少数・浅い依存なら問題ない。排除しすぎて保守性を犠牲にしない
14シート名・シート構成・名前の定義は最初の設計段階で確定させる。後からの変更は揮発性アクションの嵐になる

🔗 関連記事